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
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr);
34 use PVE
::QemuServer
::Memory
;
35 use PVE
::QemuServer
::USB
qw(parse_usb_device);
36 use PVE
::QemuServer
::Cloudinit
;
38 use Time
::HiRes
qw(gettimeofday);
39 use File
::Copy
qw(copy);
42 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
45 "$EDK2_FW_BASE/OVMF_CODE.fd",
46 "$EDK2_FW_BASE/OVMF_VARS.fd"
49 "$EDK2_FW_BASE/AAVMF_CODE.fd",
50 "$EDK2_FW_BASE/AAVMF_VARS.fd"
54 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
56 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
58 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
60 # Note about locking: we use flock on the config file protect
61 # against concurent actions.
62 # Aditionaly, we have a 'lock' setting in the config file. This
63 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
64 # allowed when such lock is set. But you can ignore this kind of
65 # lock with the --skiplock flag.
67 cfs_register_file
('/qemu-server/',
71 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
72 description
=> "Some command save/restore state from this location.",
78 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
79 description
=> "The name of the snapshot.",
80 type
=> 'string', format
=> 'pve-configid',
84 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
86 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
87 description
=> "The drive's backing file's data format.",
91 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
92 description
=> "Specifies the Qemu machine type.",
94 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
99 #no warnings 'redefine';
102 my ($controller, $vmid, $option, $value) = @_;
104 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
105 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
109 my $nodename = PVE
::INotify
::nodename
();
111 mkdir "/etc/pve/nodes/$nodename";
112 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
115 my $var_run_tmpdir = "/var/run/qemu-server";
116 mkdir $var_run_tmpdir;
118 my $lock_dir = "/var/lock/qemu-server";
121 my $pcisysfs = "/sys/bus/pci";
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.",
191 description
=> "List of additional CPU flags separated by ';'."
192 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
193 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
194 format_description
=> '+FLAG[;-FLAG...]',
196 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
205 enum
=> [qw(i6300esb ib700)],
206 description
=> "Watchdog type to emulate.",
207 default => 'i6300esb',
212 enum
=> [qw(reset shutdown poweroff pause debug none)],
213 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
217 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
221 description
=> "Enable/disable Qemu GuestAgent.",
226 fstrim_cloned_disks
=> {
227 description
=> "Run fstrim after cloning/moving a disk.",
236 description
=> "Select the VGA type.",
241 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 serial0 serial1 serial2 serial3 std virtio vmware)],
244 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
256 description
=> "Specifies whether a VM will be started during system bootup.",
262 description
=> "Automatic restart after crash (currently ignored).",
267 type
=> 'string', format
=> 'pve-hotplug-features',
268 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'.",
269 default => 'network,disk,usb',
274 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
280 description
=> "Lock/unlock the VM.",
281 enum
=> [qw(migrate backup snapshot rollback)],
286 description
=> "Limit of CPU usage.",
287 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.",
295 description
=> "CPU weight for a VM.",
296 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.",
304 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
311 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
317 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.",
325 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
326 "It should not be necessary to set it.",
327 enum
=> PVE
::Tools
::kvmkeymaplist
(),
332 type
=> 'string', format
=> 'dns-name',
333 description
=> "Set a name for the VM. Only used on the configuration web interface.",
338 description
=> "SCSI controller model",
339 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
345 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
350 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
351 description
=> "Specify guest operating system.",
352 verbose_description
=> <<EODESC,
353 Specify guest operating system. This is used to enable special
354 optimization/features for specific operating systems:
357 other;; unspecified OS
358 wxp;; Microsoft Windows XP
359 w2k;; Microsoft Windows 2000
360 w2k3;; Microsoft Windows 2003
361 w2k8;; Microsoft Windows 2008
362 wvista;; Microsoft Windows Vista
363 win7;; Microsoft Windows 7
364 win8;; Microsoft Windows 8/2012/2012r2
365 win10;; Microsoft Windows 10/2016
366 l24;; Linux 2.4 Kernel
367 l26;; Linux 2.6/3.X Kernel
368 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
374 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
375 pattern
=> '[acdn]{1,4}',
380 type
=> 'string', format
=> 'pve-qm-bootdisk',
381 description
=> "Enable booting from specified disk.",
382 pattern
=> '(ide|sata|scsi|virtio)\d+',
387 description
=> "The number of CPUs. Please use option -sockets instead.",
394 description
=> "The number of CPU sockets.",
401 description
=> "The number of cores per socket.",
408 description
=> "Enable/disable NUMA.",
414 description
=> "Enable/disable hugepages memory.",
415 enum
=> [qw(any 2 1024)],
420 description
=> "Number of hotplugged vcpus.",
427 description
=> "Enable/disable ACPI.",
432 description
=> "Enable/disable Qemu GuestAgent and its properties.",
434 format
=> $agent_fmt,
439 description
=> "Enable/disable KVM hardware virtualization.",
445 description
=> "Enable/disable time drift fix.",
451 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
456 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
460 type
=> 'string', format
=> $vga_fmt,
461 description
=> "Configure the VGA hardware.",
462 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
463 "high resolution modes (>= 1280x1024x16) you may need to increase " .
464 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
465 "is 'std' for all OS types besides some Windows versions (XP and " .
466 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
467 "display server. For win* OS you can select how many independent " .
468 "displays you want, Linux guests can add displays them self.\n".
469 "You can also run without any graphic card, using a serial device as terminal.",
473 type
=> 'string', format
=> 'pve-qm-watchdog',
474 description
=> "Create a virtual hardware watchdog device.",
475 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
476 " (by a guest action), the watchdog must be periodically polled " .
477 "by an agent inside the guest or else the watchdog will reset " .
478 "the guest (or execute the respective action specified)",
483 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
484 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'.",
485 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
488 startup
=> get_standard_option
('pve-startup-order'),
492 description
=> "Enable/disable Template.",
498 description
=> "Arbitrary arguments passed to kvm.",
499 verbose_description
=> <<EODESCR,
500 Arbitrary arguments passed to kvm, for example:
502 args: -no-reboot -no-hpet
504 NOTE: this option is for experts only.
511 description
=> "Enable/disable the USB tablet device.",
512 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
513 "usually needed to allow absolute mouse positioning with VNC. " .
514 "Else the mouse runs out of sync with normal VNC clients. " .
515 "If you're running lots of console-only guests on one host, " .
516 "you may consider disabling this to save some context switches. " .
517 "This is turned off by default if you use spice (-vga=qxl).",
522 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
526 migrate_downtime
=> {
529 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
535 type
=> 'string', format
=> 'pve-qm-ide',
536 typetext
=> '<volume>',
537 description
=> "This is an alias for option -ide2",
541 description
=> "Emulated CPU type.",
545 parent
=> get_standard_option
('pve-snapshot-name', {
547 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
551 description
=> "Timestamp for snapshots.",
557 type
=> 'string', format
=> 'pve-volume-id',
558 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
560 vmstatestorage
=> get_standard_option
('pve-storage-id', {
561 description
=> "Default storage for VM state volumes/files.",
564 runningmachine
=> get_standard_option
('pve-qemu-machine', {
565 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
567 machine
=> get_standard_option
('pve-qemu-machine'),
569 description
=> "Virtual processor architecture. Defaults to the host.",
572 enum
=> [qw(x86_64 aarch64)],
575 description
=> "Specify SMBIOS type 1 fields.",
576 type
=> 'string', format
=> 'pve-qm-smbios1',
583 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
589 enum
=> [ qw(seabios ovmf) ],
590 description
=> "Select BIOS implementation.",
591 default => 'seabios',
595 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
596 format_description
=> 'UUID',
597 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
598 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
599 " 128-bit integer value identifier to the guest OS. This allows to".
600 " notify the guest operating system when the virtual machine is".
601 " executed with a different configuration (e.g. snapshot execution".
602 " or creation from a template). The guest operating system notices".
603 " the change, and is then able to react as appropriate by marking".
604 " its copies of distributed databases as dirty, re-initializing its".
605 " random number generator, etc.\n".
606 "Note that auto-creation only works when done throug API/CLI create".
607 " or update methods, but not when manually editing the config file.",
608 default => "1 (autogenerated)",
613 my $confdesc_cloudinit = {
617 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.',
618 enum
=> ['configdrive2', 'nocloud'],
623 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
628 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.',
633 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.",
637 type
=> 'string', format
=> 'address-list',
638 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.",
643 format
=> 'urlencoded',
644 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
648 # what about other qemu settings ?
650 #machine => 'string',
663 ##soundhw => 'string',
665 while (my ($k, $v) = each %$confdesc) {
666 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
669 my $MAX_IDE_DISKS = 4;
670 my $MAX_SCSI_DISKS = 14;
671 my $MAX_VIRTIO_DISKS = 16;
672 my $MAX_SATA_DISKS = 6;
673 my $MAX_USB_DEVICES = 5;
675 my $MAX_UNUSED_DISKS = 256;
676 my $MAX_HOSTPCI_DEVICES = 4;
677 my $MAX_SERIAL_PORTS = 4;
678 my $MAX_PARALLEL_PORTS = 3;
684 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
685 description
=> "CPUs accessing this NUMA node.",
686 format_description
=> "id[-id];...",
690 description
=> "Amount of memory this NUMA node provides.",
695 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
696 description
=> "Host NUMA nodes to use.",
697 format_description
=> "id[-id];...",
702 enum
=> [qw(preferred bind interleave)],
703 description
=> "NUMA allocation policy.",
707 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
710 type
=> 'string', format
=> $numa_fmt,
711 description
=> "NUMA topology.",
713 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
715 for (my $i = 0; $i < $MAX_NUMA; $i++) {
716 $confdesc->{"numa$i"} = $numadesc;
719 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
720 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
721 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
722 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
724 my $net_fmt_bridge_descr = <<__EOD__;
725 Bridge to attach the network device to. The Proxmox VE standard bridge
728 If you do not specify a bridge, we create a kvm user (NATed) network
729 device, which provides DHCP and DNS services. The following addresses
736 The DHCP server assign addresses to the guest starting from 10.0.2.15.
742 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
743 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
744 format_description
=> "XX:XX:XX:XX:XX:XX",
749 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'.",
750 enum
=> $nic_model_list,
753 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
756 description
=> $net_fmt_bridge_descr,
757 format_description
=> 'bridge',
762 minimum
=> 0, maximum
=> 16,
763 description
=> 'Number of packet queues to be used on the device.',
769 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
774 minimum
=> 1, maximum
=> 4094,
775 description
=> 'VLAN tag to apply to packets on this interface.',
780 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
781 description
=> 'VLAN trunks to pass through this interface.',
782 format_description
=> 'vlanid[;vlanid...]',
787 description
=> 'Whether this interface should be protected by the firewall.',
792 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
799 type
=> 'string', format
=> $net_fmt,
800 description
=> "Specify network devices.",
803 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
808 format
=> 'pve-ipv4-config',
809 format_description
=> 'IPv4Format/CIDR',
810 description
=> 'IPv4 address in CIDR format.',
817 format_description
=> 'GatewayIPv4',
818 description
=> 'Default gateway for IPv4 traffic.',
824 format
=> 'pve-ipv6-config',
825 format_description
=> 'IPv6Format/CIDR',
826 description
=> 'IPv6 address in CIDR format.',
833 format_description
=> 'GatewayIPv6',
834 description
=> 'Default gateway for IPv6 traffic.',
839 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
842 type
=> 'string', format
=> 'pve-qm-ipconfig',
843 description
=> <<'EODESCR',
844 cloud-init: Specify IP addresses and gateways for the corresponding interface.
846 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
848 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
849 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
851 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
854 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
856 for (my $i = 0; $i < $MAX_NETS; $i++) {
857 $confdesc->{"net$i"} = $netdesc;
858 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
861 foreach my $key (keys %$confdesc_cloudinit) {
862 $confdesc->{$key} = $confdesc_cloudinit->{$key};
865 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
866 sub verify_volume_id_or_qm_path
{
867 my ($volid, $noerr) = @_;
869 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
873 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
874 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
876 return undef if $noerr;
884 my %drivedesc_base = (
885 volume
=> { alias
=> 'file' },
888 format
=> 'pve-volume-id-or-qm-path',
890 format_description
=> 'volume',
891 description
=> "The drive's backing volume.",
895 enum
=> [qw(cdrom disk)],
896 description
=> "The drive's media type.",
902 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
907 description
=> "Force the drive's physical geometry to have a specific head count.",
912 description
=> "Force the drive's physical geometry to have a specific sector count.",
917 enum
=> [qw(none lba auto)],
918 description
=> "Force disk geometry bios translation mode.",
923 description
=> "Controls qemu's snapshot mode feature."
924 . " If activated, changes made to the disk are temporary and will"
925 . " be discarded when the VM is shutdown.",
930 enum
=> [qw(none writethrough writeback unsafe directsync)],
931 description
=> "The drive's cache mode",
934 format
=> get_standard_option
('pve-qm-image-format'),
937 format
=> 'disk-size',
938 format_description
=> 'DiskSize',
939 description
=> "Disk size. This is purely informational and has no effect.",
944 description
=> "Whether the drive should be included when making backups.",
949 description
=> 'Whether the drive should considered for replication jobs.',
955 enum
=> [qw(ignore report stop)],
956 description
=> 'Read error action.',
961 enum
=> [qw(enospc ignore report stop)],
962 description
=> 'Write error action.',
967 enum
=> [qw(native threads)],
968 description
=> 'AIO type to use.',
973 enum
=> [qw(ignore on)],
974 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
979 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
984 format
=> 'urlencoded',
985 format_description
=> 'serial',
986 maxLength
=> 20*3, # *3 since it's %xx url enoded
987 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
992 description
=> 'Mark this locally-managed volume as available on all nodes',
993 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!",
999 my %iothread_fmt = ( iothread
=> {
1001 description
=> "Whether to use iothreads for this drive",
1008 format
=> 'urlencoded',
1009 format_description
=> 'model',
1010 maxLength
=> 40*3, # *3 since it's %xx url enoded
1011 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1019 description
=> "Number of queues.",
1025 my %scsiblock_fmt = (
1028 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",
1037 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1042 my $add_throttle_desc = sub {
1043 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1046 format_description
=> $unit,
1047 description
=> "Maximum $what in $longunit.",
1050 $d->{minimum
} = $minimum if defined($minimum);
1051 $drivedesc_base{$key} = $d;
1053 # throughput: (leaky bucket)
1054 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1055 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1056 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1057 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1058 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1059 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1060 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1061 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1062 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1064 # pools: (pool of IO before throttling starts taking effect)
1065 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1066 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1067 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1068 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1069 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1070 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1073 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1074 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1075 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1076 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1077 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1078 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1081 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1082 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1083 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1084 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1091 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1095 type
=> 'string', format
=> $ide_fmt,
1096 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1098 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1109 type
=> 'string', format
=> $scsi_fmt,
1110 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1112 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1120 type
=> 'string', format
=> $sata_fmt,
1121 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1123 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1131 type
=> 'string', format
=> $virtio_fmt,
1132 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1134 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1136 my $alldrive_fmt = {
1146 volume
=> { alias
=> 'file' },
1149 format
=> 'pve-volume-id-or-qm-path',
1151 format_description
=> 'volume',
1152 description
=> "The drive's backing volume.",
1154 format
=> get_standard_option
('pve-qm-image-format'),
1157 format
=> 'disk-size',
1158 format_description
=> 'DiskSize',
1159 description
=> "Disk size. This is purely informational and has no effect.",
1164 my $efidisk_desc = {
1166 type
=> 'string', format
=> $efidisk_fmt,
1167 description
=> "Configure a Disk for storing EFI vars",
1170 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1175 type
=> 'string', format
=> 'pve-qm-usb-device',
1176 format_description
=> 'HOSTUSBDEVICE|spice',
1177 description
=> <<EODESCR,
1178 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1180 'bus-port(.port)*' (decimal numbers) or
1181 'vendor_id:product_id' (hexadeciaml numbers) or
1184 You can use the 'lsusb -t' command to list existing usb devices.
1186 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1188 The value 'spice' can be used to add a usb redirection devices for spice.
1194 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).",
1201 type
=> 'string', format
=> $usb_fmt,
1202 description
=> "Configure an USB device (n is 0 to 4).",
1204 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1206 # NOTE: the match-groups of this regex are used in parse_hostpci
1207 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1212 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1213 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1214 description
=> <<EODESCR,
1215 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1216 of PCI virtual functions of the host. HOSTPCIID syntax is:
1218 'bus:dev.func' (hexadecimal numbers)
1220 You can us the 'lspci' command to list existing PCI devices.
1225 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1231 pattern
=> '[^,;]+',
1232 format_description
=> 'string',
1233 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1238 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1244 description
=> "Enable vfio-vga device support.",
1249 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1253 type
=> 'string', format
=> 'pve-qm-hostpci',
1254 description
=> "Map host PCI devices into guest.",
1255 verbose_description
=> <<EODESCR,
1256 Map host PCI devices into guest.
1258 NOTE: This option allows direct access to host hardware. So it is no longer
1259 possible to migrate such machines - use with special care.
1261 CAUTION: Experimental! User reported problems with this option.
1264 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1269 pattern
=> '(/dev/.+|socket)',
1270 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1271 verbose_description
=> <<EODESCR,
1272 Create a serial device inside the VM (n is 0 to 3), and pass through a
1273 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1274 host side (use 'qm terminal' to open a terminal connection).
1276 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1278 CAUTION: Experimental! User reported problems with this option.
1285 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1286 description
=> "Map host parallel devices (n is 0 to 2).",
1287 verbose_description
=> <<EODESCR,
1288 Map host parallel devices (n is 0 to 2).
1290 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1292 CAUTION: Experimental! User reported problems with this option.
1296 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1297 $confdesc->{"parallel$i"} = $paralleldesc;
1300 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1301 $confdesc->{"serial$i"} = $serialdesc;
1304 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1305 $confdesc->{"hostpci$i"} = $hostpcidesc;
1308 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1309 $drivename_hash->{"ide$i"} = 1;
1310 $confdesc->{"ide$i"} = $idedesc;
1313 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1314 $drivename_hash->{"sata$i"} = 1;
1315 $confdesc->{"sata$i"} = $satadesc;
1318 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1319 $drivename_hash->{"scsi$i"} = 1;
1320 $confdesc->{"scsi$i"} = $scsidesc ;
1323 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1324 $drivename_hash->{"virtio$i"} = 1;
1325 $confdesc->{"virtio$i"} = $virtiodesc;
1328 $drivename_hash->{efidisk0
} = 1;
1329 $confdesc->{efidisk0
} = $efidisk_desc;
1331 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1332 $confdesc->{"usb$i"} = $usbdesc;
1337 type
=> 'string', format
=> 'pve-volume-id',
1338 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1341 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1342 $confdesc->{"unused$i"} = $unuseddesc;
1345 my $kvm_api_version = 0;
1348 return $kvm_api_version if $kvm_api_version;
1350 open my $fh, '<', '/dev/kvm'
1353 # 0xae00 => KVM_GET_API_VERSION
1354 $kvm_api_version = ioctl($fh, 0xae00, 0);
1356 return $kvm_api_version;
1359 my $kvm_user_version;
1361 sub kvm_user_version
{
1363 return $kvm_user_version if $kvm_user_version;
1365 $kvm_user_version = 'unknown';
1369 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1370 $kvm_user_version = $2;
1374 eval { run_command
("kvm -version", outfunc
=> $code); };
1377 return $kvm_user_version;
1381 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1383 sub valid_drive_names
{
1384 # order is important - used to autoselect boot disk
1385 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1386 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1387 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1388 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1392 sub is_valid_drivename
{
1395 return defined($drivename_hash->{$dev});
1400 return defined($confdesc->{$key});
1404 return $nic_model_list;
1407 sub os_list_description
{
1411 wxp
=> 'Windows XP',
1412 w2k
=> 'Windows 2000',
1413 w2k3
=>, 'Windows 2003',
1414 w2k8
=> 'Windows 2008',
1415 wvista
=> 'Windows Vista',
1416 win7
=> 'Windows 7',
1417 win8
=> 'Windows 8/2012',
1418 win10
=> 'Windows 10/2016',
1426 sub get_cdrom_path
{
1428 return $cdrom_path if $cdrom_path;
1430 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1431 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1432 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1436 my ($storecfg, $vmid, $cdrom) = @_;
1438 if ($cdrom eq 'cdrom') {
1439 return get_cdrom_path
();
1440 } elsif ($cdrom eq 'none') {
1442 } elsif ($cdrom =~ m
|^/|) {
1445 return PVE
::Storage
::path
($storecfg, $cdrom);
1449 # try to convert old style file names to volume IDs
1450 sub filename_to_volume_id
{
1451 my ($vmid, $file, $media) = @_;
1453 if (!($file eq 'none' || $file eq 'cdrom' ||
1454 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1456 return undef if $file =~ m
|/|;
1458 if ($media && $media eq 'cdrom') {
1459 $file = "local:iso/$file";
1461 $file = "local:$vmid/$file";
1468 sub verify_media_type
{
1469 my ($opt, $vtype, $media) = @_;
1474 if ($media eq 'disk') {
1476 } elsif ($media eq 'cdrom') {
1479 die "internal error";
1482 return if ($vtype eq $etype);
1484 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1487 sub cleanup_drive_path
{
1488 my ($opt, $storecfg, $drive) = @_;
1490 # try to convert filesystem paths to volume IDs
1492 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1493 ($drive->{file
} !~ m
|^/dev/.+|) &&
1494 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1495 ($drive->{file
} !~ m/^\d+$/)) {
1496 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1497 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1498 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1499 verify_media_type
($opt, $vtype, $drive->{media
});
1500 $drive->{file
} = $volid;
1503 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1506 sub parse_hotplug_features
{
1511 return $res if $data eq '0';
1513 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1515 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1516 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1519 die "invalid hotplug feature '$feature'\n";
1525 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1526 sub pve_verify_hotplug_features
{
1527 my ($value, $noerr) = @_;
1529 return $value if parse_hotplug_features
($value);
1531 return undef if $noerr;
1533 die "unable to parse hotplug option\n";
1536 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1537 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1538 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1539 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1540 # [,iothread=on][,serial=serial][,model=model]
1543 my ($key, $data) = @_;
1545 my ($interface, $index);
1547 if ($key =~ m/^([^\d]+)(\d+)$/) {
1554 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1555 : $confdesc->{$key}->{format
};
1557 warn "invalid drive key: $key\n";
1560 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1561 return undef if !$res;
1562 $res->{interface
} = $interface;
1563 $res->{index} = $index;
1566 foreach my $opt (qw(bps bps_rd bps_wr)) {
1567 if (my $bps = defined(delete $res->{$opt})) {
1568 if (defined($res->{"m$opt"})) {
1569 warn "both $opt and m$opt specified\n";
1573 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1577 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1578 for my $requirement (
1579 [mbps_max
=> 'mbps'],
1580 [mbps_rd_max
=> 'mbps_rd'],
1581 [mbps_wr_max
=> 'mbps_wr'],
1582 [miops_max
=> 'miops'],
1583 [miops_rd_max
=> 'miops_rd'],
1584 [miops_wr_max
=> 'miops_wr'],
1585 [bps_max_length
=> 'mbps_max'],
1586 [bps_rd_max_length
=> 'mbps_rd_max'],
1587 [bps_wr_max_length
=> 'mbps_wr_max'],
1588 [iops_max_length
=> 'iops_max'],
1589 [iops_rd_max_length
=> 'iops_rd_max'],
1590 [iops_wr_max_length
=> 'iops_wr_max']) {
1591 my ($option, $requires) = @$requirement;
1592 if ($res->{$option} && !$res->{$requires}) {
1593 warn "$option requires $requires\n";
1598 return undef if $error;
1600 return undef if $res->{mbps_rd
} && $res->{mbps
};
1601 return undef if $res->{mbps_wr
} && $res->{mbps
};
1602 return undef if $res->{iops_rd
} && $res->{iops
};
1603 return undef if $res->{iops_wr
} && $res->{iops
};
1605 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1606 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1607 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1608 return undef if $res->{interface
} eq 'virtio';
1611 if (my $size = $res->{size
}) {
1612 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1619 my ($vmid, $drive) = @_;
1620 my $data = { %$drive };
1621 delete $data->{$_} for qw(index interface);
1622 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1626 my($fh, $noerr) = @_;
1629 my $SG_GET_VERSION_NUM = 0x2282;
1631 my $versionbuf = "\x00" x
8;
1632 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1634 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1637 my $version = unpack("I", $versionbuf);
1638 if ($version < 30000) {
1639 die "scsi generic interface too old\n" if !$noerr;
1643 my $buf = "\x00" x
36;
1644 my $sensebuf = "\x00" x
8;
1645 my $cmd = pack("C x3 C x1", 0x12, 36);
1647 # see /usr/include/scsi/sg.h
1648 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";
1650 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1651 length($sensebuf), 0, length($buf), $buf,
1652 $cmd, $sensebuf, 6000);
1654 $ret = ioctl($fh, $SG_IO, $packet);
1656 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1660 my @res = unpack($sg_io_hdr_t, $packet);
1661 if ($res[17] || $res[18]) {
1662 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1667 (my $byte0, my $byte1, $res->{vendor
},
1668 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1670 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1671 $res->{type
} = $byte0 & 31;
1679 my $fh = IO
::File-
>new("+<$path") || return undef;
1680 my $res = scsi_inquiry
($fh, 1);
1686 sub machine_type_is_q35
{
1689 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1692 sub print_tabletdevice_full
{
1693 my ($conf, $arch) = @_;
1695 my $q35 = machine_type_is_q35
($conf);
1697 # we use uhci for old VMs because tablet driver was buggy in older qemu
1699 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1705 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1708 sub print_keyboarddevice_full
{
1709 my ($conf, $arch, $machine) = @_;
1711 return undef if $arch ne 'aarch64';
1713 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1716 sub print_drivedevice_full
{
1717 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1722 if ($drive->{interface
} eq 'virtio') {
1723 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1724 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1725 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1726 } elsif ($drive->{interface
} eq 'scsi') {
1728 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1729 my $unit = $drive->{index} % $maxdev;
1730 my $devicetype = 'hd';
1732 if (drive_is_cdrom
($drive)) {
1735 if ($drive->{file
} =~ m
|^/|) {
1736 $path = $drive->{file
};
1737 if (my $info = path_is_scsi
($path)) {
1738 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1739 $devicetype = 'block';
1740 } elsif ($info->{type
} == 1) { # tape
1741 $devicetype = 'generic';
1745 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1748 if($path =~ m/^iscsi\:\/\
//){
1749 $devicetype = 'generic';
1753 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1754 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1756 $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}";
1759 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1760 $device .= ",rotation_rate=1";
1763 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1764 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1765 my $controller = int($drive->{index} / $maxdev);
1766 my $unit = $drive->{index} % $maxdev;
1767 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1769 $device = "ide-$devicetype";
1770 if ($drive->{interface
} eq 'ide') {
1771 $device .= ",bus=ide.$controller,unit=$unit";
1773 $device .= ",bus=ahci$controller.$unit";
1775 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1777 if ($devicetype eq 'hd') {
1778 if (my $model = $drive->{model
}) {
1779 $model = URI
::Escape
::uri_unescape
($model);
1780 $device .= ",model=$model";
1782 if ($drive->{ssd
}) {
1783 $device .= ",rotation_rate=1";
1786 } elsif ($drive->{interface
} eq 'usb') {
1788 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1790 die "unsupported interface type";
1793 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1795 if (my $serial = $drive->{serial
}) {
1796 $serial = URI
::Escape
::uri_unescape
($serial);
1797 $device .= ",serial=$serial";
1804 sub get_initiator_name
{
1807 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1808 while (defined(my $line = <$fh>)) {
1809 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1818 sub print_drive_full
{
1819 my ($storecfg, $vmid, $drive) = @_;
1822 my $volid = $drive->{file
};
1825 if (drive_is_cdrom
($drive)) {
1826 $path = get_iso_path
($storecfg, $vmid, $volid);
1828 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1830 $path = PVE
::Storage
::path
($storecfg, $volid);
1831 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1832 $format = qemu_img_format
($scfg, $volname);
1840 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1841 foreach my $o (@qemu_drive_options) {
1842 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1845 # snapshot only accepts on|off
1846 if (defined($drive->{snapshot
})) {
1847 my $v = $drive->{snapshot
} ?
'on' : 'off';
1848 $opts .= ",snapshot=$v";
1851 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1852 my ($dir, $qmpname) = @$type;
1853 if (my $v = $drive->{"mbps$dir"}) {
1854 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1856 if (my $v = $drive->{"mbps${dir}_max"}) {
1857 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1859 if (my $v = $drive->{"bps${dir}_max_length"}) {
1860 $opts .= ",throttling.bps$qmpname-max-length=$v";
1862 if (my $v = $drive->{"iops${dir}"}) {
1863 $opts .= ",throttling.iops$qmpname=$v";
1865 if (my $v = $drive->{"iops${dir}_max"}) {
1866 $opts .= ",throttling.iops$qmpname-max=$v";
1868 if (my $v = $drive->{"iops${dir}_max_length"}) {
1869 $opts .= ",throttling.iops$qmpname-max-length=$v";
1873 $opts .= ",format=$format" if $format && !$drive->{format
};
1875 my $cache_direct = 0;
1877 if (my $cache = $drive->{cache
}) {
1878 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1879 } elsif (!drive_is_cdrom
($drive)) {
1880 $opts .= ",cache=none";
1884 # aio native works only with O_DIRECT
1885 if (!$drive->{aio
}) {
1887 $opts .= ",aio=native";
1889 $opts .= ",aio=threads";
1893 if (!drive_is_cdrom
($drive)) {
1895 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1896 $detectzeroes = 'off';
1897 } elsif ($drive->{discard
}) {
1898 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1900 # This used to be our default with discard not being specified:
1901 $detectzeroes = 'on';
1903 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1906 my $pathinfo = $path ?
"file=$path," : '';
1908 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1911 sub print_netdevice_full
{
1912 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1914 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1916 my $device = $net->{model
};
1917 if ($net->{model
} eq 'virtio') {
1918 $device = 'virtio-net-pci';
1921 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1922 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1923 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1924 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1925 my $vectors = $net->{queues
} * 2 + 2;
1926 $tmpstr .= ",vectors=$vectors,mq=on";
1928 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1930 if ($use_old_bios_files) {
1932 if ($device eq 'virtio-net-pci') {
1933 $romfile = 'pxe-virtio.rom';
1934 } elsif ($device eq 'e1000') {
1935 $romfile = 'pxe-e1000.rom';
1936 } elsif ($device eq 'ne2k') {
1937 $romfile = 'pxe-ne2k_pci.rom';
1938 } elsif ($device eq 'pcnet') {
1939 $romfile = 'pxe-pcnet.rom';
1940 } elsif ($device eq 'rtl8139') {
1941 $romfile = 'pxe-rtl8139.rom';
1943 $tmpstr .= ",romfile=$romfile" if $romfile;
1949 sub print_netdev_full
{
1950 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1953 if ($netid =~ m/^net(\d+)$/) {
1957 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1959 my $ifname = "tap${vmid}i$i";
1961 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1962 die "interface name '$ifname' is too long (max 15 character)\n"
1963 if length($ifname) >= 16;
1965 my $vhostparam = '';
1966 if (is_native
($arch)) {
1967 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1970 my $vmname = $conf->{name
} || "vm$vmid";
1973 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1975 if ($net->{bridge
}) {
1976 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1978 $netdev = "type=user,id=$netid,hostname=$vmname";
1981 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1987 sub print_cpu_device
{
1988 my ($conf, $id) = @_;
1990 my $kvm = $conf->{kvm
} // 1;
1991 my $cpu = $kvm ?
"kvm64" : "qemu64";
1992 if (my $cputype = $conf->{cpu
}) {
1993 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1994 or die "Cannot parse cpu description: $cputype\n";
1995 $cpu = $cpuconf->{cputype
};
1998 my $cores = $conf->{cores
} || 1;
2000 my $current_core = ($id - 1) % $cores;
2001 my $current_socket = int(($id - 1 - $current_core)/$cores);
2003 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2007 'cirrus' => 'cirrus-vga',
2009 'vmware' => 'vmware-svga',
2010 'virtio' => 'virtio-vga',
2013 sub print_vga_device
{
2014 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2016 my $type = $vga_map->{$vga->{type
}};
2017 if ($type eq 'virtio-vga' && $arch eq 'aarch64') {
2018 $type = 'virtio-gpu';
2020 my $vgamem_mb = $vga->{memory
};
2022 $type = $id ?
'qxl' : 'qxl-vga';
2024 die "no devicetype for $vga->{type}\n" if !$type;
2028 if ($vga->{type
} eq 'virtio') {
2029 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2030 $memory = ",max_hostmem=$bytes";
2032 # from https://www.spice-space.org/multiple-monitors.html
2033 $memory = ",vgamem_mb=$vga->{memory}";
2034 my $ram = $vgamem_mb * 4;
2035 my $vram = $vgamem_mb * 2;
2036 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2038 $memory = ",vgamem_mb=$vga->{memory}";
2040 } elsif ($qxlnum && $id) {
2041 $memory = ",ram_size=67108864,vram_size=33554432";
2044 my $q35 = machine_type_is_q35
($conf);
2045 my $vgaid = "vga" . ($id // '');
2048 if ($q35 && $vgaid eq 'vga') {
2049 # the first display uses pcie.0 bus on q35 machines
2050 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2052 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2055 return "$type,id=${vgaid}${memory}${pciaddr}";
2058 sub drive_is_cloudinit
{
2060 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2063 sub drive_is_cdrom
{
2064 my ($drive, $exclude_cloudinit) = @_;
2066 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2068 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2072 sub parse_number_sets
{
2075 foreach my $part (split(/;/, $set)) {
2076 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2077 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2078 push @$res, [ $1, $2 ];
2080 die "invalid range: $part\n";
2089 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2090 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2091 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2098 return undef if !$value;
2100 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2102 my @idlist = split(/;/, $res->{host
});
2103 delete $res->{host
};
2104 foreach my $id (@idlist) {
2105 if ($id =~ /^$PCIRE$/) {
2107 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
2109 my $pcidevices = lspci
($1);
2110 $res->{pciid
} = $pcidevices->{$1};
2113 # should have been caught by parse_property_string already
2114 die "failed to parse PCI id: $id\n";
2120 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2124 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2129 if (!defined($res->{macaddr
})) {
2130 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2131 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2136 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2137 sub parse_ipconfig
{
2140 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2146 if ($res->{gw
} && !$res->{ip
}) {
2147 warn 'gateway specified without specifying an IP address';
2150 if ($res->{gw6
} && !$res->{ip6
}) {
2151 warn 'IPv6 gateway specified without specifying an IPv6 address';
2154 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2155 warn 'gateway specified together with DHCP';
2158 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2160 warn "IPv6 gateway specified together with $res->{ip6} address";
2164 if (!$res->{ip
} && !$res->{ip6
}) {
2165 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2174 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2177 sub add_random_macs
{
2178 my ($settings) = @_;
2180 foreach my $opt (keys %$settings) {
2181 next if $opt !~ m/^net(\d+)$/;
2182 my $net = parse_net
($settings->{$opt});
2184 $settings->{$opt} = print_net
($net);
2188 sub vm_is_volid_owner
{
2189 my ($storecfg, $vmid, $volid) = @_;
2191 if ($volid !~ m
|^/|) {
2193 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2194 if ($owner && ($owner == $vmid)) {
2202 sub split_flagged_list
{
2203 my $text = shift || '';
2204 $text =~ s/[,;]/ /g;
2206 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2209 sub join_flagged_list
{
2210 my ($how, $lst) = @_;
2211 join $how, map { $lst->{$_} . $_ } keys %$lst;
2214 sub vmconfig_delete_pending_option
{
2215 my ($conf, $key, $force) = @_;
2217 delete $conf->{pending
}->{$key};
2218 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2219 $pending_delete_hash->{$key} = $force ?
'!' : '';
2220 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2223 sub vmconfig_undelete_pending_option
{
2224 my ($conf, $key) = @_;
2226 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2227 delete $pending_delete_hash->{$key};
2229 if (%$pending_delete_hash) {
2230 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2232 delete $conf->{pending
}->{delete};
2236 sub vmconfig_register_unused_drive
{
2237 my ($storecfg, $vmid, $conf, $drive) = @_;
2239 if (drive_is_cloudinit
($drive)) {
2240 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2242 } elsif (!drive_is_cdrom
($drive)) {
2243 my $volid = $drive->{file
};
2244 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2245 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2250 sub vmconfig_cleanup_pending
{
2253 # remove pending changes when nothing changed
2255 foreach my $opt (keys %{$conf->{pending
}}) {
2256 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2258 delete $conf->{pending
}->{$opt};
2262 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2263 my $pending_delete_hash = {};
2264 while (my ($opt, $force) = each %$current_delete_hash) {
2265 if (defined($conf->{$opt})) {
2266 $pending_delete_hash->{$opt} = $force;
2272 if (%$pending_delete_hash) {
2273 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2275 delete $conf->{pending
}->{delete};
2281 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2285 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2286 format_description
=> 'UUID',
2287 description
=> "Set SMBIOS1 UUID.",
2293 format_description
=> 'string',
2294 description
=> "Set SMBIOS1 version.",
2300 format_description
=> 'string',
2301 description
=> "Set SMBIOS1 serial number.",
2307 format_description
=> 'string',
2308 description
=> "Set SMBIOS1 manufacturer.",
2314 format_description
=> 'string',
2315 description
=> "Set SMBIOS1 product ID.",
2321 format_description
=> 'string',
2322 description
=> "Set SMBIOS1 SKU string.",
2328 format_description
=> 'string',
2329 description
=> "Set SMBIOS1 family string.",
2337 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2344 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2347 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2349 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2350 sub verify_bootdisk
{
2351 my ($value, $noerr) = @_;
2353 return $value if is_valid_drivename
($value);
2355 return undef if $noerr;
2357 die "invalid boot disk '$value'\n";
2360 sub parse_watchdog
{
2363 return undef if !$value;
2365 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2370 sub parse_guest_agent
{
2373 return {} if !defined($value->{agent
});
2375 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2378 # if the agent is disabled ignore the other potentially set properties
2379 return {} if !$res->{enabled
};
2386 return {} if !$value;
2387 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2392 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2393 sub verify_usb_device
{
2394 my ($value, $noerr) = @_;
2396 return $value if parse_usb_device
($value);
2398 return undef if $noerr;
2400 die "unable to parse usb device\n";
2403 # add JSON properties for create and set function
2404 sub json_config_properties
{
2407 foreach my $opt (keys %$confdesc) {
2408 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2409 $prop->{$opt} = $confdesc->{$opt};
2415 # return copy of $confdesc_cloudinit to generate documentation
2416 sub cloudinit_config_properties
{
2418 return dclone
($confdesc_cloudinit);
2422 my ($key, $value) = @_;
2424 die "unknown setting '$key'\n" if !$confdesc->{$key};
2426 my $type = $confdesc->{$key}->{type
};
2428 if (!defined($value)) {
2429 die "got undefined value\n";
2432 if ($value =~ m/[\n\r]/) {
2433 die "property contains a line feed\n";
2436 if ($type eq 'boolean') {
2437 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2438 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2439 die "type check ('boolean') failed - got '$value'\n";
2440 } elsif ($type eq 'integer') {
2441 return int($1) if $value =~ m/^(\d+)$/;
2442 die "type check ('integer') failed - got '$value'\n";
2443 } elsif ($type eq 'number') {
2444 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2445 die "type check ('number') failed - got '$value'\n";
2446 } elsif ($type eq 'string') {
2447 if (my $fmt = $confdesc->{$key}->{format
}) {
2448 PVE
::JSONSchema
::check_format
($fmt, $value);
2451 $value =~ s/^\"(.*)\"$/$1/;
2454 die "internal error"
2458 sub check_iommu_support
{
2459 #fixme : need to check IOMMU support
2460 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2470 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2471 utime undef, undef, $conf;
2475 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2477 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2479 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2481 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2483 if ($conf->{template
}) {
2484 # check if any base image is still used by a linked clone
2485 foreach_drive
($conf, sub {
2486 my ($ds, $drive) = @_;
2488 return if drive_is_cdrom
($drive);
2490 my $volid = $drive->{file
};
2492 return if !$volid || $volid =~ m
|^/|;
2494 die "base volume '$volid' is still in use by linked cloned\n"
2495 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2500 # only remove disks owned by this VM
2501 foreach_drive
($conf, sub {
2502 my ($ds, $drive) = @_;
2504 return if drive_is_cdrom
($drive, 1);
2506 my $volid = $drive->{file
};
2508 return if !$volid || $volid =~ m
|^/|;
2510 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2511 return if !$path || !$owner || ($owner != $vmid);
2514 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2516 warn "Could not remove disk '$volid', check manually: $@" if $@;
2520 if ($keep_empty_config) {
2521 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2526 # also remove unused disk
2528 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2531 PVE
::Storage
::foreach_volid
($dl, sub {
2532 my ($volid, $sid, $volname, $d) = @_;
2533 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2542 sub parse_vm_config
{
2543 my ($filename, $raw) = @_;
2545 return undef if !defined($raw);
2548 digest
=> Digest
::SHA
::sha1_hex
($raw),
2553 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2554 || die "got strange filename '$filename'";
2562 my @lines = split(/\n/, $raw);
2563 foreach my $line (@lines) {
2564 next if $line =~ m/^\s*$/;
2566 if ($line =~ m/^\[PENDING\]\s*$/i) {
2567 $section = 'pending';
2568 if (defined($descr)) {
2570 $conf->{description
} = $descr;
2573 $conf = $res->{$section} = {};
2576 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2578 if (defined($descr)) {
2580 $conf->{description
} = $descr;
2583 $conf = $res->{snapshots
}->{$section} = {};
2587 if ($line =~ m/^\#(.*)\s*$/) {
2588 $descr = '' if !defined($descr);
2589 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2593 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2594 $descr = '' if !defined($descr);
2595 $descr .= PVE
::Tools
::decode_text
($2);
2596 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2597 $conf->{snapstate
} = $1;
2598 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2601 $conf->{$key} = $value;
2602 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2604 if ($section eq 'pending') {
2605 $conf->{delete} = $value; # we parse this later
2607 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2609 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2612 eval { $value = check_type
($key, $value); };
2614 warn "vm $vmid - unable to parse value of '$key' - $@";
2616 $key = 'ide2' if $key eq 'cdrom';
2617 my $fmt = $confdesc->{$key}->{format
};
2618 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2619 my $v = parse_drive
($key, $value);
2620 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2621 $v->{file
} = $volid;
2622 $value = print_drive
($vmid, $v);
2624 warn "vm $vmid - unable to parse value of '$key'\n";
2629 $conf->{$key} = $value;
2634 if (defined($descr)) {
2636 $conf->{description
} = $descr;
2638 delete $res->{snapstate
}; # just to be sure
2643 sub write_vm_config
{
2644 my ($filename, $conf) = @_;
2646 delete $conf->{snapstate
}; # just to be sure
2648 if ($conf->{cdrom
}) {
2649 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2650 $conf->{ide2
} = $conf->{cdrom
};
2651 delete $conf->{cdrom
};
2654 # we do not use 'smp' any longer
2655 if ($conf->{sockets
}) {
2656 delete $conf->{smp
};
2657 } elsif ($conf->{smp
}) {
2658 $conf->{sockets
} = $conf->{smp
};
2659 delete $conf->{cores
};
2660 delete $conf->{smp
};
2663 my $used_volids = {};
2665 my $cleanup_config = sub {
2666 my ($cref, $pending, $snapname) = @_;
2668 foreach my $key (keys %$cref) {
2669 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2670 $key eq 'snapstate' || $key eq 'pending';
2671 my $value = $cref->{$key};
2672 if ($key eq 'delete') {
2673 die "propertry 'delete' is only allowed in [PENDING]\n"
2675 # fixme: check syntax?
2678 eval { $value = check_type
($key, $value); };
2679 die "unable to parse value of '$key' - $@" if $@;
2681 $cref->{$key} = $value;
2683 if (!$snapname && is_valid_drivename
($key)) {
2684 my $drive = parse_drive
($key, $value);
2685 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2690 &$cleanup_config($conf);
2692 &$cleanup_config($conf->{pending
}, 1);
2694 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2695 die "internal error" if $snapname eq 'pending';
2696 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2699 # remove 'unusedX' settings if we re-add a volume
2700 foreach my $key (keys %$conf) {
2701 my $value = $conf->{$key};
2702 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2703 delete $conf->{$key};
2707 my $generate_raw_config = sub {
2708 my ($conf, $pending) = @_;
2712 # add description as comment to top of file
2713 if (defined(my $descr = $conf->{description
})) {
2715 foreach my $cl (split(/\n/, $descr)) {
2716 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2719 $raw .= "#\n" if $pending;
2723 foreach my $key (sort keys %$conf) {
2724 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2725 $raw .= "$key: $conf->{$key}\n";
2730 my $raw = &$generate_raw_config($conf);
2732 if (scalar(keys %{$conf->{pending
}})){
2733 $raw .= "\n[PENDING]\n";
2734 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2737 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2738 $raw .= "\n[$snapname]\n";
2739 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2749 # we use static defaults from our JSON schema configuration
2750 foreach my $key (keys %$confdesc) {
2751 if (defined(my $default = $confdesc->{$key}->{default})) {
2752 $res->{$key} = $default;
2760 my $vmlist = PVE
::Cluster
::get_vmlist
();
2762 return $res if !$vmlist || !$vmlist->{ids
};
2763 my $ids = $vmlist->{ids
};
2765 foreach my $vmid (keys %$ids) {
2766 my $d = $ids->{$vmid};
2767 next if !$d->{node
} || $d->{node
} ne $nodename;
2768 next if !$d->{type
} || $d->{type
} ne 'qemu';
2769 $res->{$vmid}->{exists} = 1;
2774 # test if VM uses local resources (to prevent migration)
2775 sub check_local_resources
{
2776 my ($conf, $noerr) = @_;
2780 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2781 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2783 foreach my $k (keys %$conf) {
2784 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2785 # sockets are safe: they will recreated be on the target side post-migrate
2786 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2787 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2790 die "VM uses local resources\n" if $loc_res && !$noerr;
2795 # check if used storages are available on all nodes (use by migrate)
2796 sub check_storage_availability
{
2797 my ($storecfg, $conf, $node) = @_;
2799 foreach_drive
($conf, sub {
2800 my ($ds, $drive) = @_;
2802 my $volid = $drive->{file
};
2805 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2808 # check if storage is available on both nodes
2809 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2810 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2814 # list nodes where all VM images are available (used by has_feature API)
2816 my ($conf, $storecfg) = @_;
2818 my $nodelist = PVE
::Cluster
::get_nodelist
();
2819 my $nodehash = { map { $_ => 1 } @$nodelist };
2820 my $nodename = PVE
::INotify
::nodename
();
2822 foreach_drive
($conf, sub {
2823 my ($ds, $drive) = @_;
2825 my $volid = $drive->{file
};
2828 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2830 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2831 if ($scfg->{disable
}) {
2833 } elsif (my $avail = $scfg->{nodes
}) {
2834 foreach my $node (keys %$nodehash) {
2835 delete $nodehash->{$node} if !$avail->{$node};
2837 } elsif (!$scfg->{shared
}) {
2838 foreach my $node (keys %$nodehash) {
2839 delete $nodehash->{$node} if $node ne $nodename
2849 my ($pidfile, $pid) = @_;
2851 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2855 return undef if !$line;
2856 my @param = split(/\0/, $line);
2858 my $cmd = $param[0];
2859 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2861 for (my $i = 0; $i < scalar (@param); $i++) {
2864 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2865 my $p = $param[$i+1];
2866 return 1 if $p && ($p eq $pidfile);
2875 my ($vmid, $nocheck, $node) = @_;
2877 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2879 die "unable to find configuration file for VM $vmid - no such machine\n"
2880 if !$nocheck && ! -f
$filename;
2882 my $pidfile = pidfile_name
($vmid);
2884 if (my $fd = IO
::File-
>new("<$pidfile")) {
2889 my $mtime = $st->mtime;
2890 if ($mtime > time()) {
2891 warn "file '$filename' modified in future\n";
2894 if ($line =~ m/^(\d+)$/) {
2896 if (check_cmdline
($pidfile, $pid)) {
2897 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2909 my $vzlist = config_list
();
2911 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2913 while (defined(my $de = $fd->read)) {
2914 next if $de !~ m/^(\d+)\.pid$/;
2916 next if !defined($vzlist->{$vmid});
2917 if (my $pid = check_running
($vmid)) {
2918 $vzlist->{$vmid}->{pid
} = $pid;
2926 my ($storecfg, $conf) = @_;
2928 my $bootdisk = $conf->{bootdisk
};
2929 return undef if !$bootdisk;
2930 return undef if !is_valid_drivename
($bootdisk);
2932 return undef if !$conf->{$bootdisk};
2934 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2935 return undef if !defined($drive);
2937 return undef if drive_is_cdrom
($drive);
2939 my $volid = $drive->{file
};
2940 return undef if !$volid;
2942 return $drive->{size
};
2945 our $vmstatus_return_properties = {
2946 vmid
=> get_standard_option
('pve-vmid'),
2948 description
=> "Qemu process status.",
2950 enum
=> ['stopped', 'running'],
2953 description
=> "Maximum memory in bytes.",
2956 renderer
=> 'bytes',
2959 description
=> "Root disk size in bytes.",
2962 renderer
=> 'bytes',
2965 description
=> "VM name.",
2970 description
=> "Qemu QMP agent status.",
2975 description
=> "PID of running qemu process.",
2980 description
=> "Uptime.",
2983 renderer
=> 'duration',
2986 description
=> "Maximum usable CPUs.",
2992 my $last_proc_pid_stat;
2994 # get VM status information
2995 # This must be fast and should not block ($full == false)
2996 # We only query KVM using QMP if $full == true (this can be slow)
2998 my ($opt_vmid, $full) = @_;
3002 my $storecfg = PVE
::Storage
::config
();
3004 my $list = vzlist
();
3005 my $defaults = load_defaults
();
3007 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3009 my $cpucount = $cpuinfo->{cpus
} || 1;
3011 foreach my $vmid (keys %$list) {
3012 next if $opt_vmid && ($vmid ne $opt_vmid);
3014 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3015 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3017 my $d = { vmid
=> $vmid };
3018 $d->{pid
} = $list->{$vmid}->{pid
};
3020 # fixme: better status?
3021 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3023 my $size = disksize
($storecfg, $conf);
3024 if (defined($size)) {
3025 $d->{disk
} = 0; # no info available
3026 $d->{maxdisk
} = $size;
3032 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3033 * ($conf->{cores
} || $defaults->{cores
});
3034 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3035 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3037 $d->{name
} = $conf->{name
} || "VM $vmid";
3038 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3039 : $defaults->{memory
}*(1024*1024);
3041 if ($conf->{balloon
}) {
3042 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3043 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3044 : $defaults->{shares
};
3055 $d->{diskwrite
} = 0;
3057 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3059 $d->{serial
} = 1 if conf_has_serial
($conf);
3064 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3065 foreach my $dev (keys %$netdev) {
3066 next if $dev !~ m/^tap([1-9]\d*)i/;
3068 my $d = $res->{$vmid};
3071 $d->{netout
} += $netdev->{$dev}->{receive
};
3072 $d->{netin
} += $netdev->{$dev}->{transmit
};
3075 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3076 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3081 my $ctime = gettimeofday
;
3083 foreach my $vmid (keys %$list) {
3085 my $d = $res->{$vmid};
3086 my $pid = $d->{pid
};
3089 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3090 next if !$pstat; # not running
3092 my $used = $pstat->{utime} + $pstat->{stime
};
3094 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3096 if ($pstat->{vsize
}) {
3097 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3100 my $old = $last_proc_pid_stat->{$pid};
3102 $last_proc_pid_stat->{$pid} = {
3110 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3112 if ($dtime > 1000) {
3113 my $dutime = $used - $old->{used
};
3115 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3116 $last_proc_pid_stat->{$pid} = {
3122 $d->{cpu
} = $old->{cpu
};
3126 return $res if !$full;
3128 my $qmpclient = PVE
::QMPClient-
>new();
3130 my $ballooncb = sub {
3131 my ($vmid, $resp) = @_;
3133 my $info = $resp->{'return'};
3134 return if !$info->{max_mem
};
3136 my $d = $res->{$vmid};
3138 # use memory assigned to VM
3139 $d->{maxmem
} = $info->{max_mem
};
3140 $d->{balloon
} = $info->{actual
};
3142 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3143 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3144 $d->{freemem
} = $info->{free_mem
};
3147 $d->{ballooninfo
} = $info;
3150 my $blockstatscb = sub {
3151 my ($vmid, $resp) = @_;
3152 my $data = $resp->{'return'} || [];
3153 my $totalrdbytes = 0;
3154 my $totalwrbytes = 0;
3156 for my $blockstat (@$data) {
3157 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3158 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3160 $blockstat->{device
} =~ s/drive-//;
3161 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3163 $res->{$vmid}->{diskread
} = $totalrdbytes;
3164 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3167 my $statuscb = sub {
3168 my ($vmid, $resp) = @_;
3170 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3171 # this fails if ballon driver is not loaded, so this must be
3172 # the last commnand (following command are aborted if this fails).
3173 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3175 my $status = 'unknown';
3176 if (!defined($status = $resp->{'return'}->{status
})) {
3177 warn "unable to get VM status\n";
3181 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3184 foreach my $vmid (keys %$list) {
3185 next if $opt_vmid && ($vmid ne $opt_vmid);
3186 next if !$res->{$vmid}->{pid
}; # not running
3187 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3190 $qmpclient->queue_execute(undef, 2);
3192 foreach my $vmid (keys %$list) {
3193 next if $opt_vmid && ($vmid ne $opt_vmid);
3194 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3201 my ($conf, $func, @param) = @_;
3203 foreach my $ds (valid_drive_names
()) {
3204 next if !defined($conf->{$ds});
3206 my $drive = parse_drive
($ds, $conf->{$ds});
3209 &$func($ds, $drive, @param);
3214 my ($conf, $func, @param) = @_;
3218 my $test_volid = sub {
3219 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3223 $volhash->{$volid}->{cdrom
} //= 1;
3224 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3226 $volhash->{$volid}->{replicate
} //= 0;
3227 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3229 $volhash->{$volid}->{shared
} //= 0;
3230 $volhash->{$volid}->{shared
} = 1 if $shared;
3232 $volhash->{$volid}->{referenced_in_config
} //= 0;
3233 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3235 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3236 if defined($snapname);
3239 foreach_drive
($conf, sub {
3240 my ($ds, $drive) = @_;
3241 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3244 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3245 my $snap = $conf->{snapshots
}->{$snapname};
3246 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3247 foreach_drive
($snap, sub {
3248 my ($ds, $drive) = @_;
3249 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3253 foreach my $volid (keys %$volhash) {
3254 &$func($volid, $volhash->{$volid}, @param);
3258 sub conf_has_serial
{
3261 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3262 if ($conf->{"serial$i"}) {
3270 sub vga_conf_has_spice
{
3273 my $vgaconf = parse_vga
($vga);
3274 my $vgatype = $vgaconf->{type
};
3275 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3280 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3281 sub get_host_arch
() {
3282 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3288 return get_host_arch
() eq $arch;
3291 my $default_machines = {
3296 sub get_basic_machine_info
{
3297 my ($conf, $forcemachine) = @_;
3299 my $arch = $conf->{arch
} // get_host_arch
();
3300 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3301 return ($arch, $machine);
3304 sub get_ovmf_files
($) {
3307 my $ovmf = $OVMF->{$arch}
3308 or die "no OVMF images known for architecture '$arch'\n";
3314 aarch64
=> '/usr/bin/qemu-system-aarch64',
3315 x86_64
=> '/usr/bin/qemu-system-x86_64',
3317 sub get_command_for_arch
($) {
3319 return '/usr/bin/kvm' if is_native
($arch);
3321 my $cmd = $Arch2Qemu->{$arch}
3322 or die "don't know how to emulate architecture '$arch'\n";
3326 sub get_cpu_options
{
3327 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3330 my $ostype = $conf->{ostype
};
3332 my $cpu = $kvm ?
"kvm64" : "qemu64";
3333 if ($arch eq 'aarch64') {
3334 $cpu = 'cortex-a57';
3336 if (my $cputype = $conf->{cpu
}) {
3337 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3338 or die "Cannot parse cpu description: $cputype\n";
3339 $cpu = $cpuconf->{cputype
};
3340 $kvm_off = 1 if $cpuconf->{hidden
};
3342 if (defined(my $flags = $cpuconf->{flags
})) {
3343 push @$cpuFlags, split(";", $flags);
3347 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3349 push @$cpuFlags , '-x2apic'
3350 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3352 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3354 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3356 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3358 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3359 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3362 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3364 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3366 push @$cpuFlags, 'kvm=off' if $kvm_off;
3368 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3369 push @$cpuFlags, "vendor=${cpu_vendor}"
3370 if $cpu_vendor ne 'default';
3371 } elsif ($arch ne 'aarch64') {
3372 die "internal error"; # should not happen
3375 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3377 return ('-cpu', $cpu);
3380 sub config_to_command
{
3381 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3384 my $globalFlags = [];
3385 my $machineFlags = [];
3390 my $kvmver = kvm_user_version
();
3391 my $vernum = 0; # unknown
3392 my $ostype = $conf->{ostype
};
3393 my $winversion = windows_version
($ostype);
3394 my $kvm = $conf->{kvm
};
3396 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3397 $kvm //= 1 if is_native
($arch);
3400 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3401 if !defined kvm_version
();
3404 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3405 $vernum = $1*1000000+$2*1000;
3406 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3407 $vernum = $1*1000000+$2*1000+$3;
3410 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3412 my $have_ovz = -f
'/proc/vz/vestat';
3414 my $q35 = machine_type_is_q35
($conf);
3415 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3416 my $use_old_bios_files = undef;
3417 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3419 my $cpuunits = defined($conf->{cpuunits
}) ?
3420 $conf->{cpuunits
} : $defaults->{cpuunits
};
3422 push @$cmd, get_command_for_arch
($arch);
3424 push @$cmd, '-id', $vmid;
3426 my $vmname = $conf->{name
} || "vm$vmid";
3428 push @$cmd, '-name', $vmname;
3432 my $qmpsocket = qmp_socket
($vmid);
3433 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3434 push @$cmd, '-mon', "chardev=qmp,mode=control";
3436 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3437 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3438 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3441 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3443 push @$cmd, '-daemonize';
3445 if ($conf->{smbios1
}) {
3446 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3449 if ($conf->{vmgenid
}) {
3450 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3453 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3454 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3455 die "uefi base image not found\n" if ! -f
$ovmf_code;
3459 if (my $efidisk = $conf->{efidisk0
}) {
3460 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3461 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3462 $format = $d->{format
};
3464 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3465 if (!defined($format)) {
3466 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3467 $format = qemu_img_format
($scfg, $volname);
3471 die "efidisk format must be specified\n"
3472 if !defined($format);
3475 warn "no efidisk configured! Using temporary efivars disk.\n";
3476 $path = "/tmp/$vmid-ovmf.fd";
3477 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3481 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3482 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3486 # add usb controllers
3487 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3488 push @$devices, @usbcontrollers if @usbcontrollers;
3489 my $vga = parse_vga
($conf->{vga
});
3491 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3492 $vga->{type
} = 'qxl' if $qxlnum;
3494 if (!$vga->{type
}) {
3495 if ($arch eq 'aarch64') {
3496 $vga->{type
} = 'virtio';
3497 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3498 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3500 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3504 # enable absolute mouse coordinates (needed by vnc)
3506 if (defined($conf->{tablet
})) {
3507 $tablet = $conf->{tablet
};
3509 $tablet = $defaults->{tablet
};
3510 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3511 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3515 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3516 my $kbd = print_keyboarddevice_full
($conf, $arch);
3517 push @$devices, '-device', $kbd if defined($kbd);
3521 my $gpu_passthrough;
3524 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3525 my $d = parse_hostpci
($conf->{"hostpci$i"});
3528 my $pcie = $d->{pcie
};
3530 die "q35 machine model is not enabled" if !$q35;
3531 $pciaddr = print_pcie_addr
("hostpci$i");
3533 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3536 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3537 my $romfile = $d->{romfile
};
3540 if ($d->{'x-vga'}) {
3541 $xvga = ',x-vga=on';
3543 $vga->{type
} = 'none';
3544 $gpu_passthrough = 1;
3546 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3550 my $pcidevices = $d->{pciid
};
3551 my $multifunction = 1 if @$pcidevices > 1;
3554 foreach my $pcidevice (@$pcidevices) {
3556 my $id = "hostpci$i";
3557 $id .= ".$j" if $multifunction;
3558 my $addr = $pciaddr;
3559 $addr .= ".$j" if $multifunction;
3560 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3563 $devicestr .= "$rombar$xvga";
3564 $devicestr .= ",multifunction=on" if $multifunction;
3565 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3568 push @$devices, '-device', $devicestr;
3574 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3575 push @$devices, @usbdevices if @usbdevices;
3577 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3578 if (my $path = $conf->{"serial$i"}) {
3579 if ($path eq 'socket') {
3580 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3581 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3582 # On aarch64, serial0 is the UART device. Qemu only allows
3583 # connecting UART devices via the '-serial' command line, as
3584 # the device has a fixed slot on the hardware...
3585 if ($arch eq 'aarch64' && $i == 0) {
3586 push @$devices, '-serial', "chardev:serial$i";
3588 push @$devices, '-device', "isa-serial,chardev=serial$i";
3591 die "no such serial device\n" if ! -c
$path;
3592 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3593 push @$devices, '-device', "isa-serial,chardev=serial$i";
3599 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3600 if (my $path = $conf->{"parallel$i"}) {
3601 die "no such parallel device\n" if ! -c
$path;
3602 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3603 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3604 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3610 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3611 $sockets = $conf->{sockets
} if $conf->{sockets
};
3613 my $cores = $conf->{cores
} || 1;
3615 my $maxcpus = $sockets * $cores;
3617 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3619 my $allowed_vcpus = $cpuinfo->{cpus
};
3621 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3622 if ($allowed_vcpus < $maxcpus);
3624 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3626 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3627 for (my $i = 2; $i <= $vcpus; $i++) {
3628 my $cpustr = print_cpu_device
($conf,$i);
3629 push @$cmd, '-device', $cpustr;
3634 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3636 push @$cmd, '-nodefaults';
3638 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3640 my $bootindex_hash = {};
3642 foreach my $o (split(//, $bootorder)) {
3643 $bootindex_hash->{$o} = $i*100;
3647 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3649 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3651 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3653 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3654 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3655 my $socket = vnc_socket
($vmid);
3656 push @$cmd, '-vnc', "unix:$socket,x509,password";
3658 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3659 push @$cmd, '-nographic';
3663 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3665 my $useLocaltime = $conf->{localtime};
3667 if ($winversion >= 5) { # windows
3668 $useLocaltime = 1 if !defined($conf->{localtime});
3670 # use time drift fix when acpi is enabled
3671 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3672 $tdf = 1 if !defined($conf->{tdf
});
3676 if ($winversion >= 6) {
3677 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3678 push @$cmd, '-no-hpet';
3681 push @$rtcFlags, 'driftfix=slew' if $tdf;
3684 push @$machineFlags, 'accel=tcg';
3687 if ($machine_type) {
3688 push @$machineFlags, "type=${machine_type}";
3691 if ($conf->{startdate
}) {
3692 push @$rtcFlags, "base=$conf->{startdate}";
3693 } elsif ($useLocaltime) {
3694 push @$rtcFlags, 'base=localtime';
3697 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3699 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3701 push @$cmd, '-S' if $conf->{freeze
};
3703 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3706 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3707 #push @$cmd, '-soundhw', 'es1370';
3708 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3710 if (parse_guest_agent
($conf)->{enabled
}) {
3711 my $qgasocket = qmp_socket
($vmid, 1);
3712 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3713 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3714 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3715 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3723 for(my $i = 1; $i < $qxlnum; $i++){
3724 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3727 # assume other OS works like Linux
3728 my ($ram, $vram) = ("134217728", "67108864");
3729 if ($vga->{memory
}) {
3730 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3731 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3733 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3734 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3738 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3740 my $nodename = PVE
::INotify
::nodename
();
3741 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3742 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3743 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3744 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3745 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3747 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3749 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3750 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3751 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3754 # enable balloon by default, unless explicitly disabled
3755 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3756 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3757 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3760 if ($conf->{watchdog
}) {
3761 my $wdopts = parse_watchdog
($conf->{watchdog
});
3762 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3763 my $watchdog = $wdopts->{model
} || 'i6300esb';
3764 push @$devices, '-device', "$watchdog$pciaddr";
3765 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3769 my $scsicontroller = {};
3770 my $ahcicontroller = {};
3771 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3773 # Add iscsi initiator name if available
3774 if (my $initiator = get_initiator_name
()) {
3775 push @$devices, '-iscsi', "initiator-name=$initiator";
3778 foreach_drive
($conf, sub {
3779 my ($ds, $drive) = @_;
3781 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3782 push @$vollist, $drive->{file
};
3785 # ignore efidisk here, already added in bios/fw handling code above
3786 return if $drive->{interface
} eq 'efidisk';
3788 $use_virtio = 1 if $ds =~ m/^virtio/;
3790 if (drive_is_cdrom
($drive)) {
3791 if ($bootindex_hash->{d
}) {
3792 $drive->{bootindex
} = $bootindex_hash->{d
};
3793 $bootindex_hash->{d
} += 1;
3796 if ($bootindex_hash->{c
}) {
3797 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3798 $bootindex_hash->{c
} += 1;
3802 if($drive->{interface
} eq 'virtio'){
3803 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3806 if ($drive->{interface
} eq 'scsi') {
3808 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3810 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3811 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3814 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3815 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3816 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3817 } elsif ($drive->{iothread
}) {
3818 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3822 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3823 $queues = ",num_queues=$drive->{queues}";
3826 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3827 $scsicontroller->{$controller}=1;
3830 if ($drive->{interface
} eq 'sata') {
3831 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3832 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3833 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3834 $ahcicontroller->{$controller}=1;
3837 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3838 push @$devices, '-drive',$drive_cmd;
3839 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3842 for (my $i = 0; $i < $MAX_NETS; $i++) {
3843 next if !$conf->{"net$i"};
3844 my $d = parse_net
($conf->{"net$i"});
3847 $use_virtio = 1 if $d->{model
} eq 'virtio';
3849 if ($bootindex_hash->{n
}) {
3850 $d->{bootindex
} = $bootindex_hash->{n
};
3851 $bootindex_hash->{n
} += 1;
3854 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3855 push @$devices, '-netdev', $netdevfull;
3857 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3858 push @$devices, '-device', $netdevicefull;
3863 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3868 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3870 while (my ($k, $v) = each %$bridges) {
3871 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3872 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3877 if ($conf->{args
}) {
3878 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3882 push @$cmd, @$devices;
3883 push @$cmd, '-rtc', join(',', @$rtcFlags)
3884 if scalar(@$rtcFlags);
3885 push @$cmd, '-machine', join(',', @$machineFlags)
3886 if scalar(@$machineFlags);
3887 push @$cmd, '-global', join(',', @$globalFlags)
3888 if scalar(@$globalFlags);
3890 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3895 return "${var_run_tmpdir}/$vmid.vnc";
3901 my $res = vm_mon_cmd
($vmid, 'query-spice');
3903 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3907 my ($vmid, $qga, $name) = @_;
3908 my $sockettype = $qga ?
'qga' : 'qmp';
3909 my $ext = $name ?
'-'.$name : '';
3910 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3915 return "${var_run_tmpdir}/$vmid.pid";
3918 sub vm_devices_list
{
3921 my $res = vm_mon_cmd
($vmid, 'query-pci');
3922 my $devices_to_check = [];
3924 foreach my $pcibus (@$res) {
3925 push @$devices_to_check, @{$pcibus->{devices
}},
3928 while (@$devices_to_check) {
3930 for my $d (@$devices_to_check) {
3931 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3932 next if !$d->{'pci_bridge'};
3934 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3935 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3937 $devices_to_check = $to_check;
3940 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3941 foreach my $block (@$resblock) {
3942 if($block->{device
} =~ m/^drive-(\S+)/){
3947 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3948 foreach my $mice (@$resmice) {
3949 if ($mice->{name
} eq 'QEMU HID Tablet') {
3950 $devices->{tablet
} = 1;
3955 # for usb devices there is no query-usb
3956 # but we can iterate over the entries in
3957 # qom-list path=/machine/peripheral
3958 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3959 foreach my $per (@$resperipheral) {
3960 if ($per->{name
} =~ m/^usb\d+$/) {
3961 $devices->{$per->{name
}} = 1;
3969 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3971 my $q35 = machine_type_is_q35
($conf);
3973 my $devices_list = vm_devices_list
($vmid);
3974 return 1 if defined($devices_list->{$deviceid});
3976 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
3978 if ($deviceid eq 'tablet') {
3980 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3982 } elsif ($deviceid eq 'keyboard') {
3984 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3986 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3988 die "usb hotplug currently not reliable\n";
3989 # since we can't reliably hot unplug all added usb devices
3990 # and usb passthrough disables live migration
3991 # we disable usb hotplugging for now
3992 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3994 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3996 qemu_iothread_add
($vmid, $deviceid, $device);
3998 qemu_driveadd
($storecfg, $vmid, $device);
3999 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4001 qemu_deviceadd
($vmid, $devicefull);
4002 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4004 eval { qemu_drivedel
($vmid, $deviceid); };
4009 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4012 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4013 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4014 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4016 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4018 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4019 qemu_iothread_add
($vmid, $deviceid, $device);
4020 $devicefull .= ",iothread=iothread-$deviceid";
4023 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4024 $devicefull .= ",num_queues=$device->{queues}";
4027 qemu_deviceadd
($vmid, $devicefull);
4028 qemu_deviceaddverify
($vmid, $deviceid);
4030 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4032 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4033 qemu_driveadd
($storecfg, $vmid, $device);
4035 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4036 eval { qemu_deviceadd
($vmid, $devicefull); };
4038 eval { qemu_drivedel
($vmid, $deviceid); };
4043 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4045 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4047 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4048 my $use_old_bios_files = undef;
4049 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4051 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4052 qemu_deviceadd
($vmid, $netdevicefull);
4053 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4055 eval { qemu_netdevdel
($vmid, $deviceid); };
4060 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4063 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4064 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4066 qemu_deviceadd
($vmid, $devicefull);
4067 qemu_deviceaddverify
($vmid, $deviceid);
4070 die "can't hotplug device '$deviceid'\n";
4076 # fixme: this should raise exceptions on error!
4077 sub vm_deviceunplug
{
4078 my ($vmid, $conf, $deviceid) = @_;
4080 my $devices_list = vm_devices_list
($vmid);
4081 return 1 if !defined($devices_list->{$deviceid});
4083 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4085 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4087 qemu_devicedel
($vmid, $deviceid);
4089 } elsif ($deviceid =~ m/^usb\d+$/) {
4091 die "usb hotplug currently not reliable\n";
4092 # when unplugging usb devices this way,
4093 # there may be remaining usb controllers/hubs
4094 # so we disable it for now
4095 qemu_devicedel
($vmid, $deviceid);
4096 qemu_devicedelverify
($vmid, $deviceid);
4098 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4100 qemu_devicedel
($vmid, $deviceid);
4101 qemu_devicedelverify
($vmid, $deviceid);
4102 qemu_drivedel
($vmid, $deviceid);
4103 qemu_iothread_del
($conf, $vmid, $deviceid);
4105 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4107 qemu_devicedel
($vmid, $deviceid);
4108 qemu_devicedelverify
($vmid, $deviceid);
4109 qemu_iothread_del
($conf, $vmid, $deviceid);
4111 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4113 qemu_devicedel
($vmid, $deviceid);
4114 qemu_drivedel
($vmid, $deviceid);
4115 qemu_deletescsihw
($conf, $vmid, $deviceid);
4117 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4119 qemu_devicedel
($vmid, $deviceid);
4120 qemu_devicedelverify
($vmid, $deviceid);
4121 qemu_netdevdel
($vmid, $deviceid);
4124 die "can't unplug device '$deviceid'\n";
4130 sub qemu_deviceadd
{
4131 my ($vmid, $devicefull) = @_;
4133 $devicefull = "driver=".$devicefull;
4134 my %options = split(/[=,]/, $devicefull);
4136 vm_mon_cmd
($vmid, "device_add" , %options);
4139 sub qemu_devicedel
{
4140 my ($vmid, $deviceid) = @_;
4142 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4145 sub qemu_iothread_add
{
4146 my($vmid, $deviceid, $device) = @_;
4148 if ($device->{iothread
}) {
4149 my $iothreads = vm_iothreads_list
($vmid);
4150 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4154 sub qemu_iothread_del
{
4155 my($conf, $vmid, $deviceid) = @_;
4157 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4158 if ($device->{iothread
}) {
4159 my $iothreads = vm_iothreads_list
($vmid);
4160 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4164 sub qemu_objectadd
{
4165 my($vmid, $objectid, $qomtype) = @_;
4167 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4172 sub qemu_objectdel
{
4173 my($vmid, $objectid) = @_;
4175 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4181 my ($storecfg, $vmid, $device) = @_;
4183 my $drive = print_drive_full
($storecfg, $vmid, $device);
4184 $drive =~ s/\\/\\\\/g;
4185 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4187 # If the command succeeds qemu prints: "OK
"
4188 return 1 if $ret =~ m/OK/s;
4190 die "adding drive failed
: $ret\n";
4194 my($vmid, $deviceid) = @_;
4196 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4199 return 1 if $ret eq "";
4201 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4202 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4204 die "deleting drive
$deviceid failed
: $ret\n";
4207 sub qemu_deviceaddverify {
4208 my ($vmid, $deviceid) = @_;
4210 for (my $i = 0; $i <= 5; $i++) {
4211 my $devices_list = vm_devices_list($vmid);
4212 return 1 if defined($devices_list->{$deviceid});
4216 die "error on hotplug device
'$deviceid'\n";
4220 sub qemu_devicedelverify {
4221 my ($vmid, $deviceid) = @_;
4223 # need to verify that the device is correctly removed as device_del
4224 # is async and empty return is not reliable
4226 for (my $i = 0; $i <= 5; $i++) {
4227 my $devices_list = vm_devices_list($vmid);
4228 return 1 if !defined($devices_list->{$deviceid});
4232 die "error on hot-unplugging device
'$deviceid'\n";
4235 sub qemu_findorcreatescsihw {
4236 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4238 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4240 my $scsihwid="$controller_prefix$controller";
4241 my $devices_list = vm_devices_list($vmid);
4243 if(!defined($devices_list->{$scsihwid})) {
4244 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4250 sub qemu_deletescsihw {
4251 my ($conf, $vmid, $opt) = @_;
4253 my $device = parse_drive($opt, $conf->{$opt});
4255 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4256 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4260 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4262 my $devices_list = vm_devices_list($vmid);
4263 foreach my $opt (keys %{$devices_list}) {
4264 if (PVE::QemuServer::is_valid_drivename($opt)) {
4265 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4266 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4272 my $scsihwid="scsihw
$controller";
4274 vm_deviceunplug($vmid, $conf, $scsihwid);
4279 sub qemu_add_pci_bridge {
4280 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4286 print_pci_addr($device, $bridges, $arch, $machine_type);
4288 while (my ($k, $v) = each %$bridges) {
4291 return 1 if !defined($bridgeid) || $bridgeid < 1;
4293 my $bridge = "pci
.$bridgeid";
4294 my $devices_list = vm_devices_list($vmid);
4296 if (!defined($devices_list->{$bridge})) {
4297 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4303 sub qemu_set_link_status {
4304 my ($vmid, $device, $up) = @_;
4306 vm_mon_cmd($vmid, "set_link
", name => $device,
4307 up => $up ? JSON::true : JSON::false);
4310 sub qemu_netdevadd {
4311 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4313 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4314 my %options = split(/[=,]/, $netdev);
4316 vm_mon_cmd($vmid, "netdev_add
", %options);
4320 sub qemu_netdevdel {
4321 my ($vmid, $deviceid) = @_;
4323 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4326 sub qemu_usb_hotplug {
4327 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4331 # remove the old one first
4332 vm_deviceunplug($vmid, $conf, $deviceid);
4334 # check if xhci controller is necessary and available
4335 if ($device->{usb3}) {
4337 my $devicelist = vm_devices_list($vmid);
4339 if (!$devicelist->{xhci}) {
4340 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4341 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4344 my $d = parse_usb_device($device->{host});
4345 $d->{usb3} = $device->{usb3};
4348 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4351 sub qemu_cpu_hotplug {
4352 my ($vmid, $conf, $vcpus) = @_;
4354 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4357 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4358 $sockets = $conf->{sockets} if $conf->{sockets};
4359 my $cores = $conf->{cores} || 1;
4360 my $maxcpus = $sockets * $cores;
4362 $vcpus = $maxcpus if !$vcpus;
4364 die "you can
't add more vcpus than maxcpus\n"
4365 if $vcpus > $maxcpus;
4367 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4369 if ($vcpus < $currentvcpus) {
4371 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4373 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4374 qemu_devicedel($vmid, "cpu$i");
4376 my $currentrunningvcpus = undef;
4378 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4379 last if scalar(@{$currentrunningvcpus}) == $i-1;
4380 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4384 #update conf after each succesfull cpu unplug
4385 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4386 PVE::QemuConfig->write_config($vmid, $conf);
4389 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4395 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4396 die "vcpus in running vm does not match its configuration\n"
4397 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4399 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4401 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4402 my $cpustr = print_cpu_device($conf, $i);
4403 qemu_deviceadd($vmid, $cpustr);
4406 my $currentrunningvcpus = undef;
4408 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4409 last if scalar(@{$currentrunningvcpus}) == $i;
4410 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4414 #update conf after each succesfull cpu hotplug
4415 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4416 PVE::QemuConfig->write_config($vmid, $conf);
4420 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4421 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4426 sub qemu_block_set_io_throttle {
4427 my ($vmid, $deviceid,
4428 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4429 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4430 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4431 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4433 return if !check_running($vmid) ;
4435 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4437 bps_rd => int($bps_rd),
4438 bps_wr => int($bps_wr),
4440 iops_rd => int($iops_rd),
4441 iops_wr => int($iops_wr),
4442 bps_max => int($bps_max),
4443 bps_rd_max => int($bps_rd_max),
4444 bps_wr_max => int($bps_wr_max),
4445 iops_max => int($iops_max),
4446 iops_rd_max => int($iops_rd_max),
4447 iops_wr_max => int($iops_wr_max),
4448 bps_max_length => int($bps_max_length),
4449 bps_rd_max_length => int($bps_rd_max_length),
4450 bps_wr_max_length => int($bps_wr_max_length),
4451 iops_max_length => int($iops_max_length),
4452 iops_rd_max_length => int($iops_rd_max_length),
4453 iops_wr_max_length => int($iops_wr_max_length),
4458 # old code, only used to shutdown old VM after update
4460 my ($fh, $timeout) = @_;
4462 my $sel = new IO::Select;
4469 while (scalar (@ready = $sel->can_read($timeout))) {
4471 if ($count = $fh->sysread($buf, 8192)) {
4472 if ($buf =~ /^(.*)\(qemu\) $/s) {
4479 if (!defined($count)) {
4486 die "monitor read timeout\n" if !scalar(@ready);
4491 sub qemu_block_resize {
4492 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4494 my $running = check_running($vmid);
4496 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4498 return if !$running;
4500 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4504 sub qemu_volume_snapshot {
4505 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4507 my $running = check_running($vmid);
4509 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4510 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4512 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4516 sub qemu_volume_snapshot_delete {
4517 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4519 my $running = check_running($vmid);
4524 my $conf = PVE::QemuConfig->load_config($vmid);
4525 foreach_drive($conf, sub {
4526 my ($ds, $drive) = @_;
4527 $running = 1 if $drive->{file} eq $volid;
4531 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4532 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4534 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4538 sub set_migration_caps {
4544 "auto-converge" => 1,
4546 "x-rdma-pin-all" => 0,
4551 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4553 for my $supported_capability (@$supported_capabilities) {
4555 capability => $supported_capability->{capability},
4556 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4560 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4563 my $fast_plug_option = {
4571 'vmstatestorage
' => 1,
4574 # hotplug changes in [PENDING]
4575 # $selection hash can be used to only apply specified options, for
4576 # example: { cores => 1 } (only apply changed 'cores
')
4577 # $errors ref is used to return error messages
4578 sub vmconfig_hotplug_pending {
4579 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4581 my $defaults = load_defaults();
4582 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4584 # commit values which do not have any impact on running VM first
4585 # Note: those option cannot raise errors, we we do not care about
4586 # $selection and always apply them.
4588 my $add_error = sub {
4589 my ($opt, $msg) = @_;
4590 $errors->{$opt} = "hotplug problem - $msg";
4594 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4595 if ($fast_plug_option->{$opt}) {
4596 $conf->{$opt} = $conf->{pending}->{$opt};
4597 delete $conf->{pending}->{$opt};
4603 PVE::QemuConfig->write_config($vmid, $conf);
4604 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4607 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4609 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4610 while (my ($opt, $force) = each %$pending_delete_hash) {
4611 next if $selection && !$selection->{$opt};
4613 if ($opt eq 'hotplug
') {
4614 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4615 } elsif ($opt eq 'tablet
') {
4616 die "skip\n" if !$hotplug_features->{usb};
4617 if ($defaults->{tablet}) {
4618 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4619 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4620 if $arch eq 'aarch64
';
4622 vm_deviceunplug($vmid, $conf, 'tablet
');
4623 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4625 } elsif ($opt =~ m/^usb\d+/) {
4627 # since we cannot reliably hot unplug usb devices
4628 # we are disabling it
4629 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4630 vm_deviceunplug($vmid, $conf, $opt);
4631 } elsif ($opt eq 'vcpus
') {
4632 die "skip\n" if !$hotplug_features->{cpu};
4633 qemu_cpu_hotplug($vmid, $conf, undef);
4634 } elsif ($opt eq 'balloon
') {
4635 # enable balloon device is not hotpluggable
4636 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4637 # here we reset the ballooning value to memory
4638 my $balloon = $conf->{memory} || $defaults->{memory};
4639 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4640 } elsif ($fast_plug_option->{$opt}) {
4642 } elsif ($opt =~ m/^net(\d+)$/) {
4643 die "skip\n" if !$hotplug_features->{network};
4644 vm_deviceunplug($vmid, $conf, $opt);
4645 } elsif (is_valid_drivename($opt)) {
4646 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4647 vm_deviceunplug($vmid, $conf, $opt);
4648 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4649 } elsif ($opt =~ m/^memory$/) {
4650 die "skip\n" if !$hotplug_features->{memory};
4651 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4652 } elsif ($opt eq 'cpuunits
') {
4653 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4654 } elsif ($opt eq 'cpulimit
') {
4655 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4661 &$add_error($opt, $err) if $err ne "skip\n";
4663 # save new config if hotplug was successful
4664 delete $conf->{$opt};
4665 vmconfig_undelete_pending_option($conf, $opt);
4666 PVE::QemuConfig->write_config($vmid, $conf);
4667 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4671 my $apply_pending_cloudinit;
4672 $apply_pending_cloudinit = sub {
4673 my ($key, $value) = @_;
4674 $apply_pending_cloudinit = sub {}; # once is enough
4676 my @cloudinit_opts = keys %$confdesc_cloudinit;
4677 foreach my $opt (keys %{$conf->{pending}}) {
4678 next if !grep { $_ eq $opt } @cloudinit_opts;
4679 $conf->{$opt} = delete $conf->{pending}->{$opt};
4682 my $new_conf = { %$conf };
4683 $new_conf->{$key} = $value;
4684 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4687 foreach my $opt (keys %{$conf->{pending}}) {
4688 next if $selection && !$selection->{$opt};
4689 my $value = $conf->{pending}->{$opt};
4691 if ($opt eq 'hotplug
') {
4692 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4693 } elsif ($opt eq 'tablet
') {
4694 die "skip\n" if !$hotplug_features->{usb};
4696 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4697 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4698 if $arch eq 'aarch64
';
4699 } elsif ($value == 0) {
4700 vm_deviceunplug($vmid, $conf, 'tablet
');
4701 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4703 } elsif ($opt =~ m/^usb\d+$/) {
4705 # since we cannot reliably hot unplug usb devices
4706 # we are disabling it
4707 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4708 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4709 die "skip\n" if !$d;
4710 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4711 } elsif ($opt eq 'vcpus
') {
4712 die "skip\n" if !$hotplug_features->{cpu};
4713 qemu_cpu_hotplug($vmid, $conf, $value);
4714 } elsif ($opt eq 'balloon
') {
4715 # enable/disable balloning device is not hotpluggable
4716 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4717 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4718 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4720 # allow manual ballooning if shares is set to zero
4721 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4722 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4723 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4725 } elsif ($opt =~ m/^net(\d+)$/) {
4726 # some changes can be done without hotplug
4727 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4728 $vmid, $opt, $value, $arch, $machine_type);
4729 } elsif (is_valid_drivename($opt)) {
4730 # some changes can be done without hotplug
4731 my $drive = parse_drive($opt, $value);
4732 if (drive_is_cloudinit($drive)) {
4733 &$apply_pending_cloudinit($opt, $value);
4735 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4736 $vmid, $opt, $value, 1, $arch, $machine_type);
4737 } elsif ($opt =~ m/^memory$/) { #dimms
4738 die "skip\n" if !$hotplug_features->{memory};
4739 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4740 } elsif ($opt eq 'cpuunits
') {
4741 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4742 } elsif ($opt eq 'cpulimit
') {
4743 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4744 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4746 die "skip\n"; # skip non-hot-pluggable options
4750 &$add_error($opt, $err) if $err ne "skip\n";
4752 # save new config if hotplug was successful
4753 $conf->{$opt} = $value;
4754 delete $conf->{pending}->{$opt};
4755 PVE::QemuConfig->write_config($vmid, $conf);
4756 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4761 sub try_deallocate_drive {
4762 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4764 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4765 my $volid = $drive->{file};
4766 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4767 my $sid = PVE::Storage::parse_volume_id($volid);
4768 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4770 # check if the disk is really unused
4771 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4772 if is_volume_in_use($storecfg, $conf, $key, $volid);
4773 PVE::Storage::vdisk_free($storecfg, $volid);
4776 # If vm is not owner of this disk remove from config
4784 sub vmconfig_delete_or_detach_drive {
4785 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4787 my $drive = parse_drive($opt, $conf->{$opt});
4789 my $rpcenv = PVE::RPCEnvironment::get();
4790 my $authuser = $rpcenv->get_user();
4793 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4794 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4796 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4800 sub vmconfig_apply_pending {
4801 my ($vmid, $conf, $storecfg) = @_;
4805 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4806 while (my ($opt, $force) = each %$pending_delete_hash) {
4807 die "internal error" if $opt =~ m/^unused/;
4808 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4809 if (!defined($conf->{$opt})) {
4810 vmconfig_undelete_pending_option($conf, $opt);
4811 PVE::QemuConfig->write_config($vmid, $conf);
4812 } elsif (is_valid_drivename($opt)) {
4813 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4814 vmconfig_undelete_pending_option($conf, $opt);
4815 delete $conf->{$opt};
4816 PVE::QemuConfig->write_config($vmid, $conf);
4818 vmconfig_undelete_pending_option($conf, $opt);
4819 delete $conf->{$opt};
4820 PVE::QemuConfig->write_config($vmid, $conf);
4824 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4826 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4827 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4829 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4830 # skip if nothing changed
4831 } elsif (is_valid_drivename($opt)) {
4832 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4833 if defined($conf->{$opt});
4834 $conf->{$opt} = $conf->{pending}->{$opt};
4836 $conf->{$opt} = $conf->{pending}->{$opt};
4839 delete $conf->{pending}->{$opt};
4840 PVE::QemuConfig->write_config($vmid, $conf);
4844 my $safe_num_ne = sub {
4847 return 0 if !defined($a) && !defined($b);
4848 return 1 if !defined($a);
4849 return 1 if !defined($b);
4854 my $safe_string_ne = sub {
4857 return 0 if !defined($a) && !defined($b);
4858 return 1 if !defined($a);
4859 return 1 if !defined($b);
4864 sub vmconfig_update_net {
4865 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4867 my $newnet = parse_net($value);
4869 if ($conf->{$opt}) {
4870 my $oldnet = parse_net($conf->{$opt});
4872 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4873 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4874 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4875 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4877 # for non online change, we try to hot-unplug
4878 die "skip\n" if !$hotplug;
4879 vm_deviceunplug($vmid, $conf, $opt);
4882 die "internal error" if $opt !~ m/net(\d+)/;
4883 my $iface = "tap${vmid}i$1";
4885 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4886 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4887 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4888 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4889 PVE::Network::tap_unplug($iface);
4890 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4891 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4892 # Rate can be applied on its own but any change above needs to
4893 # include the rate in tap_plug since OVS resets everything.
4894 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4897 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4898 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4906 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4912 sub vmconfig_update_disk {
4913 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
4915 # fixme: do we need force?
4917 my $drive = parse_drive($opt, $value);
4919 if ($conf->{$opt}) {
4921 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4923 my $media = $drive->{media} || 'disk
';
4924 my $oldmedia = $old_drive->{media} || 'disk
';
4925 die "unable to change media type\n" if $media ne $oldmedia;
4927 if (!drive_is_cdrom($old_drive)) {
4929 if ($drive->{file} ne $old_drive->{file}) {
4931 die "skip\n" if !$hotplug;
4933 # unplug and register as unused
4934 vm_deviceunplug($vmid, $conf, $opt);
4935 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4938 # update existing disk
4940 # skip non hotpluggable value
4941 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4942 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4943 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4944 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4949 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4950 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4951 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4952 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4953 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4954 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4955 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4956 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4957 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4958 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4959 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4960 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4961 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4962 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4963 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4964 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4965 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4966 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4968 qemu_block_set_io_throttle($vmid,"drive-$opt",
4969 ($drive->{mbps} || 0)*1024*1024,
4970 ($drive->{mbps_rd} || 0)*1024*1024,
4971 ($drive->{mbps_wr} || 0)*1024*1024,
4972 $drive->{iops} || 0,
4973 $drive->{iops_rd} || 0,
4974 $drive->{iops_wr} || 0,
4975 ($drive->{mbps_max} || 0)*1024*1024,
4976 ($drive->{mbps_rd_max} || 0)*1024*1024,
4977 ($drive->{mbps_wr_max} || 0)*1024*1024,
4978 $drive->{iops_max} || 0,
4979 $drive->{iops_rd_max} || 0,
4980 $drive->{iops_wr_max} || 0,
4981 $drive->{bps_max_length} || 1,
4982 $drive->{bps_rd_max_length} || 1,
4983 $drive->{bps_wr_max_length} || 1,
4984 $drive->{iops_max_length} || 1,
4985 $drive->{iops_rd_max_length} || 1,
4986 $drive->{iops_wr_max_length} || 1);
4995 if ($drive->{file} eq 'none
') {
4996 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4997 if (drive_is_cloudinit($old_drive)) {
4998 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5001 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5002 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5003 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5011 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5013 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5014 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5018 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5019 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5021 PVE::QemuConfig->lock_config($vmid, sub {
5022 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5024 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5026 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5028 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5030 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5031 vmconfig_apply_pending($vmid, $conf, $storecfg);
5032 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5035 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5037 my $defaults = load_defaults();
5039 # set environment variable useful inside network script
5040 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5042 my $local_volumes = {};
5044 if ($targetstorage) {
5045 foreach_drive($conf, sub {
5046 my ($ds, $drive) = @_;
5048 return if drive_is_cdrom($drive);
5050 my $volid = $drive->{file};
5054 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5056 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5057 return if $scfg->{shared};
5058 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5063 foreach my $opt (sort keys %$local_volumes) {
5065 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5066 my $drive = parse_drive($opt, $conf->{$opt});
5068 #if remote storage is specified, use default format
5069 if ($targetstorage && $targetstorage ne "1") {
5070 $storeid = $targetstorage;
5071 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5072 $format = $defFormat;
5074 #else we use same format than original
5075 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5076 $format = qemu_img_format($scfg, $volid);
5079 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5080 my $newdrive = $drive;
5081 $newdrive->{format} = $format;
5082 $newdrive->{file} = $newvolid;
5083 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5084 $local_volumes->{$opt} = $drivestr;
5085 #pass drive to conf for command line
5086 $conf->{$opt} = $drivestr;
5090 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5092 my $migrate_port = 0;
5095 if ($statefile eq 'tcp
') {
5096 my $localip = "localhost";
5097 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5098 my $nodename = PVE::INotify::nodename();
5100 if (!defined($migration_type)) {
5101 if (defined($datacenterconf->{migration}->{type})) {
5102 $migration_type = $datacenterconf->{migration}->{type};
5104 $migration_type = 'secure
';
5108 if ($migration_type eq 'insecure
') {
5109 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5110 if ($migrate_network_addr) {
5111 $localip = $migrate_network_addr;
5113 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5116 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5119 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5120 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5121 $migrate_uri = "tcp:${localip}:${migrate_port}";
5122 push @$cmd, '-incoming
', $migrate_uri;
5125 } elsif ($statefile eq 'unix
') {
5126 # should be default for secure migrations as a ssh TCP forward
5127 # tunnel is not deterministic reliable ready and fails regurarly
5128 # to set up in time, so use UNIX socket forwards
5129 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5130 unlink $socket_addr;
5132 $migrate_uri = "unix:$socket_addr";
5134 push @$cmd, '-incoming
', $migrate_uri;
5138 push @$cmd, '-loadstate
', $statefile;
5145 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5146 my $d = parse_hostpci($conf->{"hostpci$i"});
5148 my $pcidevices = $d->{pciid};
5149 foreach my $pcidevice (@$pcidevices) {
5150 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
5152 my $info = pci_device_info("0000:$pciid");
5153 die "IOMMU not present\n" if !check_iommu_support();
5154 die "no pci device info for device '$pciid'\n" if !$info;
5155 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
5156 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
5160 PVE::Storage::activate_volumes($storecfg, $vollist);
5162 if (!check_running($vmid, 1)) {
5164 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5165 outfunc => sub {}, errfunc => sub {});
5169 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5170 : $defaults->{cpuunits};
5172 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5173 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5176 Slice => 'qemu
.slice
',
5178 CPUShares => $cpuunits
5181 if (my $cpulimit = $conf->{cpulimit}) {
5182 $properties{CPUQuota} = int($cpulimit * 100);
5184 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5186 my $run_qemu = sub {
5187 PVE::Tools::run_fork sub {
5188 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5189 run_command($cmd, %run_params);
5193 if ($conf->{hugepages}) {
5196 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5197 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5199 PVE::QemuServer::Memory::hugepages_mount();
5200 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5202 eval { $run_qemu->() };
5204 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5208 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5210 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5213 eval { $run_qemu->() };
5217 # deactivate volumes if start fails
5218 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5219 die "start failed: $err";
5222 print "migration listens on $migrate_uri\n" if $migrate_uri;
5224 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5225 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5229 #start nbd server for storage migration
5230 if ($targetstorage) {
5231 my $nodename = PVE::INotify::nodename();
5232 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5233 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5234 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5235 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5237 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5239 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5241 foreach my $opt (sort keys %$local_volumes) {
5242 my $volid = $local_volumes->{$opt};
5243 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5244 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5245 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5249 if ($migratedfrom) {
5251 set_migration_caps($vmid);
5256 print "spice listens on port $spice_port\n";
5257 if ($spice_ticket) {
5258 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5259 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5264 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5265 if !$statefile && $conf->{balloon};
5267 foreach my $opt (keys %$conf) {
5268 next if $opt !~ m/^net\d+$/;
5269 my $nicconf = parse_net($conf->{$opt});
5270 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5274 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5275 path => "machine/peripheral/balloon0",
5276 property => "guest-stats-polling-interval",
5277 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5283 my ($vmid, $execute, %params) = @_;
5285 my $cmd = { execute => $execute, arguments => \%params };
5286 vm_qmp_command($vmid, $cmd);
5289 sub vm_mon_cmd_nocheck {
5290 my ($vmid, $execute, %params) = @_;
5292 my $cmd = { execute => $execute, arguments => \%params };
5293 vm_qmp_command($vmid, $cmd, 1);
5296 sub vm_qmp_command {
5297 my ($vmid, $cmd, $nocheck) = @_;
5302 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5303 $timeout = $cmd->{arguments}->{timeout};
5304 delete $cmd->{arguments}->{timeout};
5308 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5309 my $sname = qmp_socket($vmid);
5310 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5311 my $qmpclient = PVE::QMPClient->new();
5313 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5315 die "unable to open monitor socket\n";
5319 syslog("err", "VM $vmid qmp command failed - $err");
5326 sub vm_human_monitor_command {
5327 my ($vmid, $cmdline) = @_;
5332 execute => 'human-monitor-command
',
5333 arguments => { 'command-line
' => $cmdline},
5336 return vm_qmp_command($vmid, $cmd);
5339 sub vm_commandline {
5340 my ($storecfg, $vmid) = @_;
5342 my $conf = PVE::QemuConfig->load_config($vmid);
5344 my $defaults = load_defaults();
5346 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5348 return PVE::Tools::cmd2string($cmd);
5352 my ($vmid, $skiplock) = @_;
5354 PVE::QemuConfig->lock_config($vmid, sub {
5356 my $conf = PVE::QemuConfig->load_config($vmid);
5358 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5360 vm_mon_cmd($vmid, "system_reset");
5364 sub get_vm_volumes {
5368 foreach_volid($conf, sub {
5369 my ($volid, $attr) = @_;
5371 return if $volid =~ m|^/|;
5373 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5376 push @$vollist, $volid;
5382 sub vm_stop_cleanup {
5383 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5388 my $vollist = get_vm_volumes($conf);
5389 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5392 foreach my $ext (qw(mon qmp pid vnc qga)) {
5393 unlink "/var/run/qemu-server/${vmid}.$ext";
5396 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5398 warn $@ if $@; # avoid errors - just warn
5401 # Note: use $nockeck to skip tests if VM configuration file exists.
5402 # We need that when migration VMs to other nodes (files already moved)
5403 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5405 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5407 $force = 1 if !defined($force) && !$shutdown;
5410 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5411 kill 15, $pid if $pid;
5412 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5413 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5417 PVE
::QemuConfig-
>lock_config($vmid, sub {
5419 my $pid = check_running
($vmid, $nocheck);
5424 $conf = PVE
::QemuConfig-
>load_config($vmid);
5425 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5426 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5427 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5428 $timeout = $opts->{down
} if $opts->{down
};
5432 $timeout = 60 if !defined($timeout);
5436 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5437 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5439 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5442 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5449 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5454 if ($count >= $timeout) {
5456 warn "VM still running - terminating now with SIGTERM\n";
5459 die "VM quit/powerdown failed - got timeout\n";
5462 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5467 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5470 die "VM quit/powerdown failed\n";
5478 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5483 if ($count >= $timeout) {
5484 warn "VM still running - terminating now with SIGKILL\n";
5489 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5494 my ($vmid, $skiplock) = @_;
5496 PVE
::QemuConfig-
>lock_config($vmid, sub {
5498 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5500 PVE
::QemuConfig-
>check_lock($conf)
5501 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5503 vm_mon_cmd
($vmid, "stop");
5508 my ($vmid, $skiplock, $nocheck) = @_;
5510 PVE
::QemuConfig-
>lock_config($vmid, sub {
5512 my $res = vm_mon_cmd
($vmid, 'query-status');
5513 my $resume_cmd = 'cont';
5515 if ($res->{status
} && $res->{status
} eq 'suspended') {
5516 $resume_cmd = 'system_wakeup';
5521 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5523 PVE
::QemuConfig-
>check_lock($conf)
5524 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5526 vm_mon_cmd
($vmid, $resume_cmd);
5529 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5535 my ($vmid, $skiplock, $key) = @_;
5537 PVE
::QemuConfig-
>lock_config($vmid, sub {
5539 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5541 # there is no qmp command, so we use the human monitor command
5542 vm_human_monitor_command
($vmid, "sendkey $key");
5547 my ($storecfg, $vmid, $skiplock) = @_;
5549 PVE
::QemuConfig-
>lock_config($vmid, sub {
5551 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5553 if (!check_running
($vmid)) {
5554 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5556 die "VM $vmid is running - destroy failed\n";
5564 my ($filename, $buf) = @_;
5566 my $fh = IO
::File-
>new($filename, "w");
5567 return undef if !$fh;
5569 my $res = print $fh $buf;
5576 sub pci_device_info
{
5581 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5582 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5584 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5585 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5587 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5588 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5590 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5591 return undef if !defined($product) || $product !~ s/^0x//;
5596 product
=> $product,
5602 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5611 my $name = $dev->{name
};
5613 my $fn = "$pcisysfs/devices/$name/reset";
5615 return file_write
($fn, "1");
5618 sub pci_dev_bind_to_vfio
{
5621 my $name = $dev->{name
};
5623 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5625 if (!-d
$vfio_basedir) {
5626 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5628 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5630 my $testdir = "$vfio_basedir/$name";
5631 return 1 if -d
$testdir;
5633 my $data = "$dev->{vendor} $dev->{product}";
5634 return undef if !file_write
("$vfio_basedir/new_id", $data);
5636 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5637 if (!file_write
($fn, $name)) {
5638 return undef if -f
$fn;
5641 $fn = "$vfio_basedir/bind";
5642 if (! -d
$testdir) {
5643 return undef if !file_write
($fn, $name);
5649 sub pci_dev_group_bind_to_vfio
{
5652 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5654 if (!-d
$vfio_basedir) {
5655 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5657 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5659 # get IOMMU group devices
5660 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5661 my @devs = grep /^0000:/, readdir($D);
5664 foreach my $pciid (@devs) {
5665 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5667 # pci bridges, switches or root ports are not supported
5668 # they have a pci_bus subdirectory so skip them
5669 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5671 my $info = pci_device_info
($1);
5672 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5678 # vzdump restore implementaion
5680 sub tar_archive_read_firstfile
{
5681 my $archive = shift;
5683 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5685 # try to detect archive type first
5686 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5687 die "unable to open file '$archive'\n";
5688 my $firstfile = <$fh>;
5692 die "ERROR: archive contaions no data\n" if !$firstfile;
5698 sub tar_restore_cleanup
{
5699 my ($storecfg, $statfile) = @_;
5701 print STDERR
"starting cleanup\n";
5703 if (my $fd = IO
::File-
>new($statfile, "r")) {
5704 while (defined(my $line = <$fd>)) {
5705 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5708 if ($volid =~ m
|^/|) {
5709 unlink $volid || die 'unlink failed\n';
5711 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5713 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5715 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5717 print STDERR
"unable to parse line in statfile - $line";
5724 sub restore_archive
{
5725 my ($archive, $vmid, $user, $opts) = @_;
5727 my $format = $opts->{format
};
5730 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5731 $format = 'tar' if !$format;
5733 } elsif ($archive =~ m/\.tar$/) {
5734 $format = 'tar' if !$format;
5735 } elsif ($archive =~ m/.tar.lzo$/) {
5736 $format = 'tar' if !$format;
5738 } elsif ($archive =~ m/\.vma$/) {
5739 $format = 'vma' if !$format;
5740 } elsif ($archive =~ m/\.vma\.gz$/) {
5741 $format = 'vma' if !$format;
5743 } elsif ($archive =~ m/\.vma\.lzo$/) {
5744 $format = 'vma' if !$format;
5747 $format = 'vma' if !$format; # default
5750 # try to detect archive format
5751 if ($format eq 'tar') {
5752 return restore_tar_archive
($archive, $vmid, $user, $opts);
5754 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5758 sub restore_update_config_line
{
5759 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5761 return if $line =~ m/^\#qmdump\#/;
5762 return if $line =~ m/^\#vzdump\#/;
5763 return if $line =~ m/^lock:/;
5764 return if $line =~ m/^unused\d+:/;
5765 return if $line =~ m/^parent:/;
5766 return if $line =~ m/^template:/; # restored VM is never a template
5768 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5769 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5770 # try to convert old 1.X settings
5771 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5772 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5773 my ($model, $macaddr) = split(/\=/, $devconfig);
5774 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5777 bridge
=> "vmbr$ind",
5778 macaddr
=> $macaddr,
5780 my $netstr = print_net
($net);
5782 print $outfd "net$cookie->{netcount}: $netstr\n";
5783 $cookie->{netcount
}++;
5785 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5786 my ($id, $netstr) = ($1, $2);
5787 my $net = parse_net
($netstr);
5788 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5789 $netstr = print_net
($net);
5790 print $outfd "$id: $netstr\n";
5791 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5794 my $di = parse_drive
($virtdev, $value);
5795 if (defined($di->{backup
}) && !$di->{backup
}) {
5796 print $outfd "#$line";
5797 } elsif ($map->{$virtdev}) {
5798 delete $di->{format
}; # format can change on restore
5799 $di->{file
} = $map->{$virtdev};
5800 $value = print_drive
($vmid, $di);
5801 print $outfd "$virtdev: $value\n";
5805 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5807 if ($vmgenid ne '0') {
5808 # always generate a new vmgenid if there was a valid one setup
5809 $vmgenid = generate_uuid
();
5811 print $outfd "vmgenid: $vmgenid\n";
5812 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5813 my ($uuid, $uuid_str);
5814 UUID
::generate
($uuid);
5815 UUID
::unparse
($uuid, $uuid_str);
5816 my $smbios1 = parse_smbios1
($2);
5817 $smbios1->{uuid
} = $uuid_str;
5818 print $outfd $1.print_smbios1
($smbios1)."\n";
5825 my ($cfg, $vmid) = @_;
5827 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5829 my $volid_hash = {};
5830 foreach my $storeid (keys %$info) {
5831 foreach my $item (@{$info->{$storeid}}) {
5832 next if !($item->{volid
} && $item->{size
});
5833 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5834 $volid_hash->{$item->{volid
}} = $item;
5841 sub is_volume_in_use
{
5842 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5844 my $path = PVE
::Storage
::path
($storecfg, $volid);
5846 my $scan_config = sub {
5847 my ($cref, $snapname) = @_;
5849 foreach my $key (keys %$cref) {
5850 my $value = $cref->{$key};
5851 if (is_valid_drivename
($key)) {
5852 next if $skip_drive && $key eq $skip_drive;
5853 my $drive = parse_drive
($key, $value);
5854 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5855 return 1 if $volid eq $drive->{file
};
5856 if ($drive->{file
} =~ m!^/!) {
5857 return 1 if $drive->{file
} eq $path;
5859 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5861 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5863 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5871 return 1 if &$scan_config($conf);
5875 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5876 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5882 sub update_disksize
{
5883 my ($vmid, $conf, $volid_hash) = @_;
5886 my $prefix = "VM $vmid:";
5888 # used and unused disks
5889 my $referenced = {};
5891 # Note: it is allowed to define multiple storages with same path (alias), so
5892 # we need to check both 'volid' and real 'path' (two different volid can point
5893 # to the same path).
5895 my $referencedpath = {};
5898 foreach my $opt (keys %$conf) {
5899 if (is_valid_drivename
($opt)) {
5900 my $drive = parse_drive
($opt, $conf->{$opt});
5901 my $volid = $drive->{file
};
5904 $referenced->{$volid} = 1;
5905 if ($volid_hash->{$volid} &&
5906 (my $path = $volid_hash->{$volid}->{path
})) {
5907 $referencedpath->{$path} = 1;
5910 next if drive_is_cdrom
($drive);
5911 next if !$volid_hash->{$volid};
5913 $drive->{size
} = $volid_hash->{$volid}->{size
};
5914 my $new = print_drive
($vmid, $drive);
5915 if ($new ne $conf->{$opt}) {
5917 $conf->{$opt} = $new;
5918 print "$prefix update disk '$opt' information.\n";
5923 # remove 'unusedX' entry if volume is used
5924 foreach my $opt (keys %$conf) {
5925 next if $opt !~ m/^unused\d+$/;
5926 my $volid = $conf->{$opt};
5927 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5928 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5929 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5931 delete $conf->{$opt};
5934 $referenced->{$volid} = 1;
5935 $referencedpath->{$path} = 1 if $path;
5938 foreach my $volid (sort keys %$volid_hash) {
5939 next if $volid =~ m/vm-$vmid-state-/;
5940 next if $referenced->{$volid};
5941 my $path = $volid_hash->{$volid}->{path
};
5942 next if !$path; # just to be sure
5943 next if $referencedpath->{$path};
5945 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5946 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5947 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5954 my ($vmid, $nolock, $dryrun) = @_;
5956 my $cfg = PVE
::Storage
::config
();
5958 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5959 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5960 foreach my $stor (keys %{$cfg->{ids
}}) {
5961 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5964 print "rescan volumes...\n";
5965 my $volid_hash = scan_volids
($cfg, $vmid);
5967 my $updatefn = sub {
5970 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5972 PVE
::QemuConfig-
>check_lock($conf);
5975 foreach my $volid (keys %$volid_hash) {
5976 my $info = $volid_hash->{$volid};
5977 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5980 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5982 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5985 if (defined($vmid)) {
5989 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5992 my $vmlist = config_list
();
5993 foreach my $vmid (keys %$vmlist) {
5997 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6003 sub restore_vma_archive
{
6004 my ($archive, $vmid, $user, $opts, $comp) = @_;
6006 my $readfrom = $archive;
6008 my $cfg = PVE
::Storage
::config
();
6010 my $bwlimit = $opts->{bwlimit
};
6012 my $dbg_cmdstring = '';
6013 my $add_pipe = sub {
6015 push @$commands, $cmd;
6016 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6017 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6022 if ($archive eq '-') {
6025 # If we use a backup from a PVE defined storage we also consider that
6026 # storage's rate limit:
6027 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6028 if (defined($volid)) {
6029 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6030 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6032 print STDERR
"applying read rate limit: $readlimit\n";
6033 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6034 $add_pipe->($cstream);
6041 if ($comp eq 'gzip') {
6042 $cmd = ['zcat', $readfrom];
6043 } elsif ($comp eq 'lzop') {
6044 $cmd = ['lzop', '-d', '-c', $readfrom];
6046 die "unknown compression method '$comp'\n";
6051 my $tmpdir = "/var/tmp/vzdumptmp$$";
6054 # disable interrupts (always do cleanups)
6058 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6060 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6061 POSIX
::mkfifo
($mapfifo, 0600);
6064 my $openfifo = sub {
6065 open($fifofh, '>', $mapfifo) || die $!;
6068 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6075 my $rpcenv = PVE
::RPCEnvironment
::get
();
6077 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6078 my $tmpfn = "$conffile.$$.tmp";
6080 # Note: $oldconf is undef if VM does not exists
6081 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6082 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6086 my $print_devmap = sub {
6087 my $virtdev_hash = {};
6089 my $cfgfn = "$tmpdir/qemu-server.conf";
6091 # we can read the config - that is already extracted
6092 my $fh = IO
::File-
>new($cfgfn, "r") ||
6093 "unable to read qemu-server.conf - $!\n";
6095 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6097 my $pve_firewall_dir = '/etc/pve/firewall';
6098 mkdir $pve_firewall_dir; # make sure the dir exists
6099 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6102 while (defined(my $line = <$fh>)) {
6103 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6104 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6105 die "archive does not contain data for drive '$virtdev'\n"
6106 if !$devinfo->{$devname};
6107 if (defined($opts->{storage
})) {
6108 $storeid = $opts->{storage
} || 'local';
6109 } elsif (!$storeid) {
6112 $format = 'raw' if !$format;
6113 $devinfo->{$devname}->{devname
} = $devname;
6114 $devinfo->{$devname}->{virtdev
} = $virtdev;
6115 $devinfo->{$devname}->{format
} = $format;
6116 $devinfo->{$devname}->{storeid
} = $storeid;
6118 # check permission on storage
6119 my $pool = $opts->{pool
}; # todo: do we need that?
6120 if ($user ne 'root@pam') {
6121 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6124 $storage_limits{$storeid} = $bwlimit;
6126 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6130 foreach my $key (keys %storage_limits) {
6131 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6133 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6134 $storage_limits{$key} = $limit * 1024;
6137 foreach my $devname (keys %$devinfo) {
6138 die "found no device mapping information for device '$devname'\n"
6139 if !$devinfo->{$devname}->{virtdev
};
6142 # create empty/temp config
6144 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6145 foreach_drive
($oldconf, sub {
6146 my ($ds, $drive) = @_;
6148 return if drive_is_cdrom
($drive);
6150 my $volid = $drive->{file
};
6152 return if !$volid || $volid =~ m
|^/|;
6154 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6155 return if !$path || !$owner || ($owner != $vmid);
6157 # Note: only delete disk we want to restore
6158 # other volumes will become unused
6159 if ($virtdev_hash->{$ds}) {
6160 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6167 # delete vmstate files
6168 # since after the restore we have no snapshots anymore
6169 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6170 my $snap = $oldconf->{snapshots
}->{$snapname};
6171 if ($snap->{vmstate
}) {
6172 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6181 foreach my $virtdev (sort keys %$virtdev_hash) {
6182 my $d = $virtdev_hash->{$virtdev};
6183 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6184 my $storeid = $d->{storeid
};
6185 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6188 if (my $limit = $storage_limits{$storeid}) {
6189 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6192 # test if requested format is supported
6193 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6194 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6195 $d->{format
} = $defFormat if !$supported;
6197 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6198 $d->{format
}, undef, $alloc_size);
6199 print STDERR
"new volume ID is '$volid'\n";
6200 $d->{volid
} = $volid;
6201 my $path = PVE
::Storage
::path
($cfg, $volid);
6203 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6205 my $write_zeros = 1;
6206 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6210 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6212 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6213 $map->{$virtdev} = $volid;
6216 $fh->seek(0, 0) || die "seek failed - $!\n";
6218 my $outfd = new IO
::File
($tmpfn, "w") ||
6219 die "unable to write config for VM $vmid\n";
6221 my $cookie = { netcount
=> 0 };
6222 while (defined(my $line = <$fh>)) {
6223 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6236 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6237 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6239 $oldtimeout = alarm($timeout);
6246 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6247 my ($dev_id, $size, $devname) = ($1, $2, $3);
6248 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6249 } elsif ($line =~ m/^CTIME: /) {
6250 # we correctly received the vma config, so we can disable
6251 # the timeout now for disk allocation (set to 10 minutes, so
6252 # that we always timeout if something goes wrong)
6255 print $fifofh "done\n";
6256 my $tmp = $oldtimeout || 0;
6257 $oldtimeout = undef;
6263 print "restore vma archive: $dbg_cmdstring\n";
6264 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6268 alarm($oldtimeout) if $oldtimeout;
6271 foreach my $devname (keys %$devinfo) {
6272 my $volid = $devinfo->{$devname}->{volid
};
6273 push @$vollist, $volid if $volid;
6276 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6284 foreach my $devname (keys %$devinfo) {
6285 my $volid = $devinfo->{$devname}->{volid
};
6288 if ($volid =~ m
|^/|) {
6289 unlink $volid || die 'unlink failed\n';
6291 PVE
::Storage
::vdisk_free
($cfg, $volid);
6293 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6295 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6302 rename($tmpfn, $conffile) ||
6303 die "unable to commit configuration file '$conffile'\n";
6305 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6307 eval { rescan
($vmid, 1); };
6311 sub restore_tar_archive
{
6312 my ($archive, $vmid, $user, $opts) = @_;
6314 if ($archive ne '-') {
6315 my $firstfile = tar_archive_read_firstfile
($archive);
6316 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6317 if $firstfile ne 'qemu-server.conf';
6320 my $storecfg = PVE
::Storage
::config
();
6322 # destroy existing data - keep empty config
6323 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6324 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6326 my $tocmd = "/usr/lib/qemu-server/qmextract";
6328 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6329 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6330 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6331 $tocmd .= ' --info' if $opts->{info
};
6333 # tar option "xf" does not autodetect compression when read from STDIN,
6334 # so we pipe to zcat
6335 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6336 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6338 my $tmpdir = "/var/tmp/vzdumptmp$$";
6341 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6342 local $ENV{VZDUMP_VMID
} = $vmid;
6343 local $ENV{VZDUMP_USER
} = $user;
6345 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6346 my $tmpfn = "$conffile.$$.tmp";
6348 # disable interrupts (always do cleanups)
6352 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6360 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6362 if ($archive eq '-') {
6363 print "extracting archive from STDIN\n";
6364 run_command
($cmd, input
=> "<&STDIN");
6366 print "extracting archive '$archive'\n";
6370 return if $opts->{info
};
6374 my $statfile = "$tmpdir/qmrestore.stat";
6375 if (my $fd = IO
::File-
>new($statfile, "r")) {
6376 while (defined (my $line = <$fd>)) {
6377 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6378 $map->{$1} = $2 if $1;
6380 print STDERR
"unable to parse line in statfile - $line\n";
6386 my $confsrc = "$tmpdir/qemu-server.conf";
6388 my $srcfd = new IO
::File
($confsrc, "r") ||
6389 die "unable to open file '$confsrc'\n";
6391 my $outfd = new IO
::File
($tmpfn, "w") ||
6392 die "unable to write config for VM $vmid\n";
6394 my $cookie = { netcount
=> 0 };
6395 while (defined (my $line = <$srcfd>)) {
6396 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6408 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6415 rename $tmpfn, $conffile ||
6416 die "unable to commit configuration file '$conffile'\n";
6418 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6420 eval { rescan
($vmid, 1); };
6424 sub foreach_storage_used_by_vm
{
6425 my ($conf, $func) = @_;
6429 foreach_drive
($conf, sub {
6430 my ($ds, $drive) = @_;
6431 return if drive_is_cdrom
($drive);
6433 my $volid = $drive->{file
};
6435 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6436 $sidhash->{$sid} = $sid if $sid;
6439 foreach my $sid (sort keys %$sidhash) {
6444 sub do_snapshots_with_qemu
{
6445 my ($storecfg, $volid) = @_;
6447 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6449 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6450 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6454 if ($volid =~ m/\.(qcow2|qed)$/){
6461 sub qga_check_running
{
6462 my ($vmid, $nowarn) = @_;
6464 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6466 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6472 sub template_create
{
6473 my ($vmid, $conf, $disk) = @_;
6475 my $storecfg = PVE
::Storage
::config
();
6477 foreach_drive
($conf, sub {
6478 my ($ds, $drive) = @_;
6480 return if drive_is_cdrom
($drive);
6481 return if $disk && $ds ne $disk;
6483 my $volid = $drive->{file
};
6484 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6486 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6487 $drive->{file
} = $voliddst;
6488 $conf->{$ds} = print_drive
($vmid, $drive);
6489 PVE
::QemuConfig-
>write_config($vmid, $conf);
6493 sub qemu_img_convert
{
6494 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6496 my $storecfg = PVE
::Storage
::config
();
6497 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6498 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6500 if ($src_storeid && $dst_storeid) {
6502 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6504 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6505 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6507 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6508 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6510 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6511 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6514 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6515 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6516 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6517 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6518 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6519 if ($is_zero_initialized) {
6520 push @$cmd, "zeroinit:$dst_path";
6522 push @$cmd, $dst_path;
6527 if($line =~ m/\((\S+)\/100\
%\)/){
6529 my $transferred = int($size * $percent / 100);
6530 my $remaining = $size - $transferred;
6532 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6537 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6539 die "copy failed: $err" if $err;
6543 sub qemu_img_format
{
6544 my ($scfg, $volname) = @_;
6546 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6553 sub qemu_drive_mirror
{
6554 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6556 $jobs = {} if !$jobs;
6560 $jobs->{"drive-$drive"} = {};
6562 if ($dst_volid =~ /^nbd:/) {
6563 $qemu_target = $dst_volid;
6566 my $storecfg = PVE
::Storage
::config
();
6567 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6569 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6571 $format = qemu_img_format
($dst_scfg, $dst_volname);
6573 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6575 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6578 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6579 $opts->{format
} = $format if $format;
6581 print "drive mirror is starting for drive-$drive\n";
6583 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6586 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6587 die "mirroring error: $err";
6590 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6593 sub qemu_drive_mirror_monitor
{
6594 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6597 my $err_complete = 0;
6600 die "storage migration timed out\n" if $err_complete > 300;
6602 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6604 my $running_mirror_jobs = {};
6605 foreach my $stat (@$stats) {
6606 next if $stat->{type
} ne 'mirror';
6607 $running_mirror_jobs->{$stat->{device
}} = $stat;
6610 my $readycounter = 0;
6612 foreach my $job (keys %$jobs) {
6614 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6615 print "$job : finished\n";
6616 delete $jobs->{$job};
6620 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6622 my $busy = $running_mirror_jobs->{$job}->{busy
};
6623 my $ready = $running_mirror_jobs->{$job}->{ready
};
6624 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6625 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6626 my $remaining = $total - $transferred;
6627 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6629 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6632 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6635 last if scalar(keys %$jobs) == 0;
6637 if ($readycounter == scalar(keys %$jobs)) {
6638 print "all mirroring jobs are ready \n";
6639 last if $skipcomplete; #do the complete later
6641 if ($vmiddst && $vmiddst != $vmid) {
6642 my $agent_running = $qga && qga_check_running
($vmid);
6643 if ($agent_running) {
6644 print "freeze filesystem\n";
6645 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6647 print "suspend vm\n";
6648 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6651 # if we clone a disk for a new target vm, we don't switch the disk
6652 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6654 if ($agent_running) {
6655 print "unfreeze filesystem\n";
6656 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6658 print "resume vm\n";
6659 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6665 foreach my $job (keys %$jobs) {
6666 # try to switch the disk if source and destination are on the same guest
6667 print "$job: Completing block job...\n";
6669 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6670 if ($@ =~ m/cannot be completed/) {
6671 print "$job: Block job cannot be completed, try again.\n";
6674 print "$job: Completed successfully.\n";
6675 $jobs->{$job}->{complete
} = 1;
6686 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6687 die "mirroring error: $err";
6692 sub qemu_blockjobs_cancel
{
6693 my ($vmid, $jobs) = @_;
6695 foreach my $job (keys %$jobs) {
6696 print "$job: Cancelling block job\n";
6697 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6698 $jobs->{$job}->{cancel
} = 1;
6702 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6704 my $running_jobs = {};
6705 foreach my $stat (@$stats) {
6706 $running_jobs->{$stat->{device
}} = $stat;
6709 foreach my $job (keys %$jobs) {
6711 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6712 print "$job: Done.\n";
6713 delete $jobs->{$job};
6717 last if scalar(keys %$jobs) == 0;
6724 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6725 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6730 print "create linked clone of drive $drivename ($drive->{file})\n";
6731 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6732 push @$newvollist, $newvolid;
6735 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6736 $storeid = $storage if $storage;
6738 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6739 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6741 print "create full clone of drive $drivename ($drive->{file})\n";
6743 if (drive_is_cloudinit
($drive)) {
6744 $name = "vm-$newvmid-cloudinit";
6745 # cloudinit only supports raw and qcow2 atm:
6746 if ($dst_format eq 'qcow2') {
6748 } elsif ($dst_format ne 'raw') {
6749 die "clone: unhandled format for cloudinit image\n";
6752 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6753 push @$newvollist, $newvolid;
6755 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6757 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6758 if (!$running || $snapname) {
6759 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6762 my $kvmver = get_running_qemu_version
($vmid);
6763 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6764 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6765 if $drive->{iothread
};
6768 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6772 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6775 $disk->{format
} = undef;
6776 $disk->{file
} = $newvolid;
6777 $disk->{size
} = $size;
6782 # this only works if VM is running
6783 sub get_current_qemu_machine
{
6786 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6787 my $res = vm_qmp_command
($vmid, $cmd);
6789 my ($current, $default);
6790 foreach my $e (@$res) {
6791 $default = $e->{name
} if $e->{'is-default'};
6792 $current = $e->{name
} if $e->{'is-current'};
6795 # fallback to the default machine if current is not supported by qemu
6796 return $current || $default || 'pc';
6799 sub get_running_qemu_version
{
6801 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6802 my $res = vm_qmp_command
($vmid, $cmd);
6803 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6806 sub qemu_machine_feature_enabled
{
6807 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6812 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6814 $current_major = $3;
6815 $current_minor = $4;
6817 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6819 $current_major = $1;
6820 $current_minor = $2;
6823 return 1 if $current_major > $version_major ||
6824 ($current_major == $version_major &&
6825 $current_minor >= $version_minor);
6828 sub qemu_machine_pxe
{
6829 my ($vmid, $conf, $machine) = @_;
6831 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6833 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6840 sub qemu_use_old_bios_files
{
6841 my ($machine_type) = @_;
6843 return if !$machine_type;
6845 my $use_old_bios_files = undef;
6847 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6849 $use_old_bios_files = 1;
6851 my $kvmver = kvm_user_version
();
6852 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6853 # load new efi bios files on migration. So this hack is required to allow
6854 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6855 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6856 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6859 return ($use_old_bios_files, $machine_type);
6862 sub create_efidisk
($$$$$) {
6863 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6865 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6866 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6868 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6869 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6870 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6872 my $path = PVE
::Storage
::path
($storecfg, $volid);
6874 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6876 die "Copying EFI vars image failed: $@" if $@;
6878 return ($volid, $vars_size);
6885 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6886 my (undef, $id, $function) = @_;
6887 my $res = { id
=> $id, function
=> $function};
6888 push @{$devices->{$id}}, $res;
6891 # Entries should be sorted by functions.
6892 foreach my $id (keys %$devices) {
6893 my $dev = $devices->{$id};
6894 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6900 sub vm_iothreads_list
{
6903 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6906 foreach my $iothread (@$res) {
6907 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6914 my ($conf, $drive) = @_;
6918 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6920 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6926 my $controller = int($drive->{index} / $maxdev);
6927 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6929 return ($maxdev, $controller, $controller_prefix);
6932 sub add_hyperv_enlightenments
{
6933 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6935 return if $winversion < 6;
6936 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6938 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6940 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6941 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6942 push @$cpuFlags , 'hv_vapic';
6943 push @$cpuFlags , 'hv_time';
6945 push @$cpuFlags , 'hv_spinlocks=0xffff';
6948 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6949 push @$cpuFlags , 'hv_reset';
6950 push @$cpuFlags , 'hv_vpindex';
6951 push @$cpuFlags , 'hv_runtime';
6954 if ($winversion >= 7) {
6955 push @$cpuFlags , 'hv_relaxed';
6957 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6958 push @$cpuFlags , 'hv_synic';
6959 push @$cpuFlags , 'hv_stimer';
6964 sub windows_version
{
6967 return 0 if !$ostype;
6971 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6973 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6975 } elsif ($ostype =~ m/^win(\d+)$/) {
6982 sub resolve_dst_disk_format
{
6983 my ($storecfg, $storeid, $src_volname, $format) = @_;
6984 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6987 # if no target format is specified, use the source disk format as hint
6989 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6990 $format = qemu_img_format
($scfg, $src_volname);
6996 # test if requested format is supported - else use default
6997 my $supported = grep { $_ eq $format } @$validFormats;
6998 $format = $defFormat if !$supported;
7002 sub resolve_first_disk
{
7004 my @disks = PVE
::QemuServer
::valid_drive_names
();
7006 foreach my $ds (reverse @disks) {
7007 next if !$conf->{$ds};
7008 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
7009 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
7016 my ($uuid, $uuid_str);
7017 UUID
::generate
($uuid);
7018 UUID
::unparse
($uuid, $uuid_str);
7022 sub generate_smbios1_uuid
{
7023 return "uuid=".generate_uuid
();
7029 vm_mon_cmd
($vmid, 'nbd-server-stop');
7032 # bash completion helper
7034 sub complete_backup_archives
{
7035 my ($cmdname, $pname, $cvalue) = @_;
7037 my $cfg = PVE
::Storage
::config
();
7041 if ($cvalue =~ m/^([^:]+):/) {
7045 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7048 foreach my $id (keys %$data) {
7049 foreach my $item (@{$data->{$id}}) {
7050 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7051 push @$res, $item->{volid
} if defined($item->{volid
});
7058 my $complete_vmid_full = sub {
7061 my $idlist = vmstatus
();
7065 foreach my $id (keys %$idlist) {
7066 my $d = $idlist->{$id};
7067 if (defined($running)) {
7068 next if $d->{template
};
7069 next if $running && $d->{status
} ne 'running';
7070 next if !$running && $d->{status
} eq 'running';
7079 return &$complete_vmid_full();
7082 sub complete_vmid_stopped
{
7083 return &$complete_vmid_full(0);
7086 sub complete_vmid_running
{
7087 return &$complete_vmid_full(1);
7090 sub complete_storage
{
7092 my $cfg = PVE
::Storage
::config
();
7093 my $ids = $cfg->{ids
};
7096 foreach my $sid (keys %$ids) {
7097 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7098 next if !$ids->{$sid}->{content
}->{images
};