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
;
39 use Time
::HiRes
qw(gettimeofday);
40 use File
::Copy
qw(copy);
43 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
46 "$EDK2_FW_BASE/OVMF_CODE.fd",
47 "$EDK2_FW_BASE/OVMF_VARS.fd"
50 "$EDK2_FW_BASE/AAVMF_CODE.fd",
51 "$EDK2_FW_BASE/AAVMF_VARS.fd"
55 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
57 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
59 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
61 # Note about locking: we use flock on the config file protect
62 # against concurent actions.
63 # Aditionaly, we have a 'lock' setting in the config file. This
64 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
65 # allowed when such lock is set. But you can ignore this kind of
66 # lock with the --skiplock flag.
68 cfs_register_file
('/qemu-server/',
72 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
73 description
=> "Some command save/restore state from this location.",
79 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
80 description
=> "The name of the snapshot.",
81 type
=> 'string', format
=> 'pve-configid',
85 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
87 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
88 description
=> "The drive's backing file's data format.",
92 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
93 description
=> "Specifies the Qemu machine type.",
95 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
100 #no warnings 'redefine';
103 my ($controller, $vmid, $option, $value) = @_;
105 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
106 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
110 my $nodename = PVE
::INotify
::nodename
();
112 mkdir "/etc/pve/nodes/$nodename";
113 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
116 my $var_run_tmpdir = "/var/run/qemu-server";
117 mkdir $var_run_tmpdir;
119 my $lock_dir = "/var/lock/qemu-server";
122 my $cpu_vendor_list = {
124 486 => 'GenuineIntel',
125 pentium
=> 'GenuineIntel',
126 pentium2
=> 'GenuineIntel',
127 pentium3
=> 'GenuineIntel',
128 coreduo
=> 'GenuineIntel',
129 core2duo
=> 'GenuineIntel',
130 Conroe
=> 'GenuineIntel',
131 Penryn
=> 'GenuineIntel',
132 Nehalem
=> 'GenuineIntel',
133 'Nehalem-IBRS' => 'GenuineIntel',
134 Westmere
=> 'GenuineIntel',
135 'Westmere-IBRS' => 'GenuineIntel',
136 SandyBridge
=> 'GenuineIntel',
137 'SandyBridge-IBRS' => 'GenuineIntel',
138 IvyBridge
=> 'GenuineIntel',
139 'IvyBridge-IBRS' => 'GenuineIntel',
140 Haswell
=> 'GenuineIntel',
141 'Haswell-IBRS' => 'GenuineIntel',
142 'Haswell-noTSX' => 'GenuineIntel',
143 'Haswell-noTSX-IBRS' => 'GenuineIntel',
144 Broadwell
=> 'GenuineIntel',
145 'Broadwell-IBRS' => 'GenuineIntel',
146 'Broadwell-noTSX' => 'GenuineIntel',
147 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
148 'Skylake-Client' => 'GenuineIntel',
149 'Skylake-Client-IBRS' => 'GenuineIntel',
150 'Skylake-Server' => 'GenuineIntel',
151 'Skylake-Server-IBRS' => 'GenuineIntel',
154 athlon
=> 'AuthenticAMD',
155 phenom
=> 'AuthenticAMD',
156 Opteron_G1
=> 'AuthenticAMD',
157 Opteron_G2
=> 'AuthenticAMD',
158 Opteron_G3
=> 'AuthenticAMD',
159 Opteron_G4
=> 'AuthenticAMD',
160 Opteron_G5
=> 'AuthenticAMD',
161 EPYC
=> 'AuthenticAMD',
162 'EPYC-IBPB' => 'AuthenticAMD',
164 # generic types, use vendor from host node
173 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
177 description
=> "Emulated CPU type.",
179 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
184 description
=> "Do not identify as a KVM virtual machine.",
191 pattern
=> qr/[a-zA-Z0-9]{1,12}/,
192 format_description
=> 'vendor-id',
193 description
=> 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.',
197 description
=> "List of additional CPU flags separated by ';'."
198 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
199 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
200 format_description
=> '+FLAG[;-FLAG...]',
202 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
211 enum
=> [qw(i6300esb ib700)],
212 description
=> "Watchdog type to emulate.",
213 default => 'i6300esb',
218 enum
=> [qw(reset shutdown poweroff pause debug none)],
219 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
223 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
227 description
=> "Enable/disable Qemu GuestAgent.",
232 fstrim_cloned_disks
=> {
233 description
=> "Run fstrim after cloning/moving a disk.",
242 description
=> "Select the VGA type.",
247 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
250 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
262 description
=> "Specifies whether a VM will be started during system bootup.",
268 description
=> "Automatic restart after crash (currently ignored).",
273 type
=> 'string', format
=> 'pve-hotplug-features',
274 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'.",
275 default => 'network,disk,usb',
280 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
286 description
=> "Lock/unlock the VM.",
287 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete)],
292 description
=> "Limit of CPU usage.",
293 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.",
301 description
=> "CPU weight for a VM.",
302 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.",
310 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
317 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
323 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.",
331 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
332 "It should not be necessary to set it.",
333 enum
=> PVE
::Tools
::kvmkeymaplist
(),
338 type
=> 'string', format
=> 'dns-name',
339 description
=> "Set a name for the VM. Only used on the configuration web interface.",
344 description
=> "SCSI controller model",
345 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
351 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
356 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
357 description
=> "Specify guest operating system.",
358 verbose_description
=> <<EODESC,
359 Specify guest operating system. This is used to enable special
360 optimization/features for specific operating systems:
363 other;; unspecified OS
364 wxp;; Microsoft Windows XP
365 w2k;; Microsoft Windows 2000
366 w2k3;; Microsoft Windows 2003
367 w2k8;; Microsoft Windows 2008
368 wvista;; Microsoft Windows Vista
369 win7;; Microsoft Windows 7
370 win8;; Microsoft Windows 8/2012/2012r2
371 win10;; Microsoft Windows 10/2016
372 l24;; Linux 2.4 Kernel
373 l26;; Linux 2.6/3.X Kernel
374 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
380 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
381 pattern
=> '[acdn]{1,4}',
386 type
=> 'string', format
=> 'pve-qm-bootdisk',
387 description
=> "Enable booting from specified disk.",
388 pattern
=> '(ide|sata|scsi|virtio)\d+',
393 description
=> "The number of CPUs. Please use option -sockets instead.",
400 description
=> "The number of CPU sockets.",
407 description
=> "The number of cores per socket.",
414 description
=> "Enable/disable NUMA.",
420 description
=> "Enable/disable hugepages memory.",
421 enum
=> [qw(any 2 1024)],
426 description
=> "Number of hotplugged vcpus.",
433 description
=> "Enable/disable ACPI.",
438 description
=> "Enable/disable Qemu GuestAgent and its properties.",
440 format
=> $agent_fmt,
445 description
=> "Enable/disable KVM hardware virtualization.",
451 description
=> "Enable/disable time drift fix.",
457 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
462 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
466 type
=> 'string', format
=> $vga_fmt,
467 description
=> "Configure the VGA hardware.",
468 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
469 "high resolution modes (>= 1280x1024x16) you may need to increase " .
470 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
471 "is 'std' for all OS types besides some Windows versions (XP and " .
472 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
473 "display server. For win* OS you can select how many independent " .
474 "displays you want, Linux guests can add displays them self.\n".
475 "You can also run without any graphic card, using a serial device as terminal.",
479 type
=> 'string', format
=> 'pve-qm-watchdog',
480 description
=> "Create a virtual hardware watchdog device.",
481 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
482 " (by a guest action), the watchdog must be periodically polled " .
483 "by an agent inside the guest or else the watchdog will reset " .
484 "the guest (or execute the respective action specified)",
489 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
490 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'.",
491 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
494 startup
=> get_standard_option
('pve-startup-order'),
498 description
=> "Enable/disable Template.",
504 description
=> "Arbitrary arguments passed to kvm.",
505 verbose_description
=> <<EODESCR,
506 Arbitrary arguments passed to kvm, for example:
508 args: -no-reboot -no-hpet
510 NOTE: this option is for experts only.
517 description
=> "Enable/disable the USB tablet device.",
518 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
519 "usually needed to allow absolute mouse positioning with VNC. " .
520 "Else the mouse runs out of sync with normal VNC clients. " .
521 "If you're running lots of console-only guests on one host, " .
522 "you may consider disabling this to save some context switches. " .
523 "This is turned off by default if you use spice (-vga=qxl).",
528 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
532 migrate_downtime
=> {
535 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
541 type
=> 'string', format
=> 'pve-qm-ide',
542 typetext
=> '<volume>',
543 description
=> "This is an alias for option -ide2",
547 description
=> "Emulated CPU type.",
551 parent
=> get_standard_option
('pve-snapshot-name', {
553 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
557 description
=> "Timestamp for snapshots.",
563 type
=> 'string', format
=> 'pve-volume-id',
564 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
566 vmstatestorage
=> get_standard_option
('pve-storage-id', {
567 description
=> "Default storage for VM state volumes/files.",
570 runningmachine
=> get_standard_option
('pve-qemu-machine', {
571 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
573 machine
=> get_standard_option
('pve-qemu-machine'),
575 description
=> "Virtual processor architecture. Defaults to the host.",
578 enum
=> [qw(x86_64 aarch64)],
581 description
=> "Specify SMBIOS type 1 fields.",
582 type
=> 'string', format
=> 'pve-qm-smbios1',
589 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
595 enum
=> [ qw(seabios ovmf) ],
596 description
=> "Select BIOS implementation.",
597 default => 'seabios',
601 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
602 format_description
=> 'UUID',
603 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
604 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
605 " 128-bit integer value identifier to the guest OS. This allows to".
606 " notify the guest operating system when the virtual machine is".
607 " executed with a different configuration (e.g. snapshot execution".
608 " or creation from a template). The guest operating system notices".
609 " the change, and is then able to react as appropriate by marking".
610 " its copies of distributed databases as dirty, re-initializing its".
611 " random number generator, etc.\n".
612 "Note that auto-creation only works when done throug API/CLI create".
613 " or update methods, but not when manually editing the config file.",
614 default => "1 (autogenerated)",
619 my $confdesc_cloudinit = {
623 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.',
624 enum
=> ['configdrive2', 'nocloud'],
629 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
634 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.',
639 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.",
643 type
=> 'string', format
=> 'address-list',
644 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.",
649 format
=> 'urlencoded',
650 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
654 # what about other qemu settings ?
656 #machine => 'string',
669 ##soundhw => 'string',
671 while (my ($k, $v) = each %$confdesc) {
672 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
675 my $MAX_IDE_DISKS = 4;
676 my $MAX_SCSI_DISKS = 14;
677 my $MAX_VIRTIO_DISKS = 16;
678 my $MAX_SATA_DISKS = 6;
679 my $MAX_USB_DEVICES = 5;
681 my $MAX_UNUSED_DISKS = 256;
682 my $MAX_HOSTPCI_DEVICES = 4;
683 my $MAX_SERIAL_PORTS = 4;
684 my $MAX_PARALLEL_PORTS = 3;
690 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
691 description
=> "CPUs accessing this NUMA node.",
692 format_description
=> "id[-id];...",
696 description
=> "Amount of memory this NUMA node provides.",
701 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
702 description
=> "Host NUMA nodes to use.",
703 format_description
=> "id[-id];...",
708 enum
=> [qw(preferred bind interleave)],
709 description
=> "NUMA allocation policy.",
713 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
716 type
=> 'string', format
=> $numa_fmt,
717 description
=> "NUMA topology.",
719 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
721 for (my $i = 0; $i < $MAX_NUMA; $i++) {
722 $confdesc->{"numa$i"} = $numadesc;
725 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
726 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
727 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
728 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
730 my $net_fmt_bridge_descr = <<__EOD__;
731 Bridge to attach the network device to. The Proxmox VE standard bridge
734 If you do not specify a bridge, we create a kvm user (NATed) network
735 device, which provides DHCP and DNS services. The following addresses
742 The DHCP server assign addresses to the guest starting from 10.0.2.15.
748 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
749 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
750 format_description
=> "XX:XX:XX:XX:XX:XX",
755 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'.",
756 enum
=> $nic_model_list,
759 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
762 description
=> $net_fmt_bridge_descr,
763 format_description
=> 'bridge',
768 minimum
=> 0, maximum
=> 16,
769 description
=> 'Number of packet queues to be used on the device.',
775 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
780 minimum
=> 1, maximum
=> 4094,
781 description
=> 'VLAN tag to apply to packets on this interface.',
786 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
787 description
=> 'VLAN trunks to pass through this interface.',
788 format_description
=> 'vlanid[;vlanid...]',
793 description
=> 'Whether this interface should be protected by the firewall.',
798 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
805 type
=> 'string', format
=> $net_fmt,
806 description
=> "Specify network devices.",
809 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
814 format
=> 'pve-ipv4-config',
815 format_description
=> 'IPv4Format/CIDR',
816 description
=> 'IPv4 address in CIDR format.',
823 format_description
=> 'GatewayIPv4',
824 description
=> 'Default gateway for IPv4 traffic.',
830 format
=> 'pve-ipv6-config',
831 format_description
=> 'IPv6Format/CIDR',
832 description
=> 'IPv6 address in CIDR format.',
839 format_description
=> 'GatewayIPv6',
840 description
=> 'Default gateway for IPv6 traffic.',
845 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
848 type
=> 'string', format
=> 'pve-qm-ipconfig',
849 description
=> <<'EODESCR',
850 cloud-init: Specify IP addresses and gateways for the corresponding interface.
852 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
854 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
855 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
857 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
860 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
862 for (my $i = 0; $i < $MAX_NETS; $i++) {
863 $confdesc->{"net$i"} = $netdesc;
864 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
867 foreach my $key (keys %$confdesc_cloudinit) {
868 $confdesc->{$key} = $confdesc_cloudinit->{$key};
871 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
872 sub verify_volume_id_or_qm_path
{
873 my ($volid, $noerr) = @_;
875 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
879 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
880 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
882 return undef if $noerr;
890 my %drivedesc_base = (
891 volume
=> { alias
=> 'file' },
894 format
=> 'pve-volume-id-or-qm-path',
896 format_description
=> 'volume',
897 description
=> "The drive's backing volume.",
901 enum
=> [qw(cdrom disk)],
902 description
=> "The drive's media type.",
908 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
913 description
=> "Force the drive's physical geometry to have a specific head count.",
918 description
=> "Force the drive's physical geometry to have a specific sector count.",
923 enum
=> [qw(none lba auto)],
924 description
=> "Force disk geometry bios translation mode.",
929 description
=> "Controls qemu's snapshot mode feature."
930 . " If activated, changes made to the disk are temporary and will"
931 . " be discarded when the VM is shutdown.",
936 enum
=> [qw(none writethrough writeback unsafe directsync)],
937 description
=> "The drive's cache mode",
940 format
=> get_standard_option
('pve-qm-image-format'),
943 format
=> 'disk-size',
944 format_description
=> 'DiskSize',
945 description
=> "Disk size. This is purely informational and has no effect.",
950 description
=> "Whether the drive should be included when making backups.",
955 description
=> 'Whether the drive should considered for replication jobs.',
961 enum
=> [qw(ignore report stop)],
962 description
=> 'Read error action.',
967 enum
=> [qw(enospc ignore report stop)],
968 description
=> 'Write error action.',
973 enum
=> [qw(native threads)],
974 description
=> 'AIO type to use.',
979 enum
=> [qw(ignore on)],
980 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
985 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
990 format
=> 'urlencoded',
991 format_description
=> 'serial',
992 maxLength
=> 20*3, # *3 since it's %xx url enoded
993 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
998 description
=> 'Mark this locally-managed volume as available on all nodes',
999 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!",
1005 my %iothread_fmt = ( iothread
=> {
1007 description
=> "Whether to use iothreads for this drive",
1014 format
=> 'urlencoded',
1015 format_description
=> 'model',
1016 maxLength
=> 40*3, # *3 since it's %xx url enoded
1017 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1025 description
=> "Number of queues.",
1031 my %scsiblock_fmt = (
1034 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",
1043 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1048 my $add_throttle_desc = sub {
1049 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1052 format_description
=> $unit,
1053 description
=> "Maximum $what in $longunit.",
1056 $d->{minimum
} = $minimum if defined($minimum);
1057 $drivedesc_base{$key} = $d;
1059 # throughput: (leaky bucket)
1060 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1061 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1062 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1063 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1064 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1065 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1066 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1067 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1068 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1070 # pools: (pool of IO before throttling starts taking effect)
1071 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1072 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1073 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1074 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1075 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1076 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1079 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1080 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1081 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1082 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1083 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1084 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1087 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1088 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1089 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1090 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1097 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1101 type
=> 'string', format
=> $ide_fmt,
1102 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1104 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1115 type
=> 'string', format
=> $scsi_fmt,
1116 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1118 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1126 type
=> 'string', format
=> $sata_fmt,
1127 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1129 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1137 type
=> 'string', format
=> $virtio_fmt,
1138 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1140 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1142 my $alldrive_fmt = {
1152 volume
=> { alias
=> 'file' },
1155 format
=> 'pve-volume-id-or-qm-path',
1157 format_description
=> 'volume',
1158 description
=> "The drive's backing volume.",
1160 format
=> get_standard_option
('pve-qm-image-format'),
1163 format
=> 'disk-size',
1164 format_description
=> 'DiskSize',
1165 description
=> "Disk size. This is purely informational and has no effect.",
1170 my $efidisk_desc = {
1172 type
=> 'string', format
=> $efidisk_fmt,
1173 description
=> "Configure a Disk for storing EFI vars",
1176 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1181 type
=> 'string', format
=> 'pve-qm-usb-device',
1182 format_description
=> 'HOSTUSBDEVICE|spice',
1183 description
=> <<EODESCR,
1184 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1186 'bus-port(.port)*' (decimal numbers) or
1187 'vendor_id:product_id' (hexadeciaml numbers) or
1190 You can use the 'lsusb -t' command to list existing usb devices.
1192 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1194 The value 'spice' can be used to add a usb redirection devices for spice.
1200 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).",
1207 type
=> 'string', format
=> $usb_fmt,
1208 description
=> "Configure an USB device (n is 0 to 4).",
1210 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1212 my $PCIRE = qr/[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1217 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1218 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1219 description
=> <<EODESCR,
1220 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1221 of PCI virtual functions of the host. HOSTPCIID syntax is:
1223 'bus:dev.func' (hexadecimal numbers)
1225 You can us the 'lspci' command to list existing PCI devices.
1230 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1236 pattern
=> '[^,;]+',
1237 format_description
=> 'string',
1238 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1243 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1249 description
=> "Enable vfio-vga device support.",
1255 format_description
=> 'string',
1256 pattern
=> '[^/\.:]+',
1258 description
=> <<EODESCR
1259 The type of mediated device to use.
1260 An instance of this type will be created on startup of the VM and
1261 will be cleaned up when the VM stops.
1265 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1269 type
=> 'string', format
=> 'pve-qm-hostpci',
1270 description
=> "Map host PCI devices into guest.",
1271 verbose_description
=> <<EODESCR,
1272 Map host PCI devices into guest.
1274 NOTE: This option allows direct access to host hardware. So it is no longer
1275 possible to migrate such machines - use with special care.
1277 CAUTION: Experimental! User reported problems with this option.
1280 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1285 pattern
=> '(/dev/.+|socket)',
1286 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1287 verbose_description
=> <<EODESCR,
1288 Create a serial device inside the VM (n is 0 to 3), and pass through a
1289 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1290 host side (use 'qm terminal' to open a terminal connection).
1292 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1294 CAUTION: Experimental! User reported problems with this option.
1301 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1302 description
=> "Map host parallel devices (n is 0 to 2).",
1303 verbose_description
=> <<EODESCR,
1304 Map host parallel devices (n is 0 to 2).
1306 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1308 CAUTION: Experimental! User reported problems with this option.
1312 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1313 $confdesc->{"parallel$i"} = $paralleldesc;
1316 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1317 $confdesc->{"serial$i"} = $serialdesc;
1320 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1321 $confdesc->{"hostpci$i"} = $hostpcidesc;
1324 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1325 $drivename_hash->{"ide$i"} = 1;
1326 $confdesc->{"ide$i"} = $idedesc;
1329 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1330 $drivename_hash->{"sata$i"} = 1;
1331 $confdesc->{"sata$i"} = $satadesc;
1334 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1335 $drivename_hash->{"scsi$i"} = 1;
1336 $confdesc->{"scsi$i"} = $scsidesc ;
1339 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1340 $drivename_hash->{"virtio$i"} = 1;
1341 $confdesc->{"virtio$i"} = $virtiodesc;
1344 $drivename_hash->{efidisk0
} = 1;
1345 $confdesc->{efidisk0
} = $efidisk_desc;
1347 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1348 $confdesc->{"usb$i"} = $usbdesc;
1353 type
=> 'string', format
=> 'pve-volume-id',
1354 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1357 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1358 $confdesc->{"unused$i"} = $unuseddesc;
1361 my $kvm_api_version = 0;
1364 return $kvm_api_version if $kvm_api_version;
1366 open my $fh, '<', '/dev/kvm'
1369 # 0xae00 => KVM_GET_API_VERSION
1370 $kvm_api_version = ioctl($fh, 0xae00, 0);
1372 return $kvm_api_version;
1375 my $kvm_user_version;
1377 sub kvm_user_version
{
1379 return $kvm_user_version if $kvm_user_version;
1381 $kvm_user_version = 'unknown';
1385 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1386 $kvm_user_version = $2;
1390 eval { run_command
("kvm -version", outfunc
=> $code); };
1393 return $kvm_user_version;
1397 sub kernel_has_vhost_net
{
1398 return -c
'/dev/vhost-net';
1401 sub valid_drive_names
{
1402 # order is important - used to autoselect boot disk
1403 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1404 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1405 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1406 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1410 sub is_valid_drivename
{
1413 return defined($drivename_hash->{$dev});
1418 return defined($confdesc->{$key});
1422 return $nic_model_list;
1425 sub os_list_description
{
1429 wxp
=> 'Windows XP',
1430 w2k
=> 'Windows 2000',
1431 w2k3
=>, 'Windows 2003',
1432 w2k8
=> 'Windows 2008',
1433 wvista
=> 'Windows Vista',
1434 win7
=> 'Windows 7',
1435 win8
=> 'Windows 8/2012',
1436 win10
=> 'Windows 10/2016',
1444 sub get_cdrom_path
{
1446 return $cdrom_path if $cdrom_path;
1448 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1449 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1450 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1454 my ($storecfg, $vmid, $cdrom) = @_;
1456 if ($cdrom eq 'cdrom') {
1457 return get_cdrom_path
();
1458 } elsif ($cdrom eq 'none') {
1460 } elsif ($cdrom =~ m
|^/|) {
1463 return PVE
::Storage
::path
($storecfg, $cdrom);
1467 # try to convert old style file names to volume IDs
1468 sub filename_to_volume_id
{
1469 my ($vmid, $file, $media) = @_;
1471 if (!($file eq 'none' || $file eq 'cdrom' ||
1472 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1474 return undef if $file =~ m
|/|;
1476 if ($media && $media eq 'cdrom') {
1477 $file = "local:iso/$file";
1479 $file = "local:$vmid/$file";
1486 sub verify_media_type
{
1487 my ($opt, $vtype, $media) = @_;
1492 if ($media eq 'disk') {
1494 } elsif ($media eq 'cdrom') {
1497 die "internal error";
1500 return if ($vtype eq $etype);
1502 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1505 sub cleanup_drive_path
{
1506 my ($opt, $storecfg, $drive) = @_;
1508 # try to convert filesystem paths to volume IDs
1510 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1511 ($drive->{file
} !~ m
|^/dev/.+|) &&
1512 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1513 ($drive->{file
} !~ m/^\d+$/)) {
1514 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1515 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1516 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1517 verify_media_type
($opt, $vtype, $drive->{media
});
1518 $drive->{file
} = $volid;
1521 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1524 sub parse_hotplug_features
{
1529 return $res if $data eq '0';
1531 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1533 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1534 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1537 die "invalid hotplug feature '$feature'\n";
1543 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1544 sub pve_verify_hotplug_features
{
1545 my ($value, $noerr) = @_;
1547 return $value if parse_hotplug_features
($value);
1549 return undef if $noerr;
1551 die "unable to parse hotplug option\n";
1554 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1555 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1556 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1557 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1558 # [,iothread=on][,serial=serial][,model=model]
1561 my ($key, $data) = @_;
1563 my ($interface, $index);
1565 if ($key =~ m/^([^\d]+)(\d+)$/) {
1572 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1573 : $confdesc->{$key}->{format
};
1575 warn "invalid drive key: $key\n";
1578 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1579 return undef if !$res;
1580 $res->{interface
} = $interface;
1581 $res->{index} = $index;
1584 foreach my $opt (qw(bps bps_rd bps_wr)) {
1585 if (my $bps = defined(delete $res->{$opt})) {
1586 if (defined($res->{"m$opt"})) {
1587 warn "both $opt and m$opt specified\n";
1591 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1595 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1596 for my $requirement (
1597 [mbps_max
=> 'mbps'],
1598 [mbps_rd_max
=> 'mbps_rd'],
1599 [mbps_wr_max
=> 'mbps_wr'],
1600 [miops_max
=> 'miops'],
1601 [miops_rd_max
=> 'miops_rd'],
1602 [miops_wr_max
=> 'miops_wr'],
1603 [bps_max_length
=> 'mbps_max'],
1604 [bps_rd_max_length
=> 'mbps_rd_max'],
1605 [bps_wr_max_length
=> 'mbps_wr_max'],
1606 [iops_max_length
=> 'iops_max'],
1607 [iops_rd_max_length
=> 'iops_rd_max'],
1608 [iops_wr_max_length
=> 'iops_wr_max']) {
1609 my ($option, $requires) = @$requirement;
1610 if ($res->{$option} && !$res->{$requires}) {
1611 warn "$option requires $requires\n";
1616 return undef if $error;
1618 return undef if $res->{mbps_rd
} && $res->{mbps
};
1619 return undef if $res->{mbps_wr
} && $res->{mbps
};
1620 return undef if $res->{iops_rd
} && $res->{iops
};
1621 return undef if $res->{iops_wr
} && $res->{iops
};
1623 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1624 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1625 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1626 return undef if $res->{interface
} eq 'virtio';
1629 if (my $size = $res->{size
}) {
1630 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1637 my ($vmid, $drive) = @_;
1638 my $data = { %$drive };
1639 delete $data->{$_} for qw(index interface);
1640 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1644 my($fh, $noerr) = @_;
1647 my $SG_GET_VERSION_NUM = 0x2282;
1649 my $versionbuf = "\x00" x
8;
1650 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1652 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1655 my $version = unpack("I", $versionbuf);
1656 if ($version < 30000) {
1657 die "scsi generic interface too old\n" if !$noerr;
1661 my $buf = "\x00" x
36;
1662 my $sensebuf = "\x00" x
8;
1663 my $cmd = pack("C x3 C x1", 0x12, 36);
1665 # see /usr/include/scsi/sg.h
1666 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";
1668 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1669 length($sensebuf), 0, length($buf), $buf,
1670 $cmd, $sensebuf, 6000);
1672 $ret = ioctl($fh, $SG_IO, $packet);
1674 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1678 my @res = unpack($sg_io_hdr_t, $packet);
1679 if ($res[17] || $res[18]) {
1680 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1685 (my $byte0, my $byte1, $res->{vendor
},
1686 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1688 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1689 $res->{type
} = $byte0 & 31;
1697 my $fh = IO
::File-
>new("+<$path") || return undef;
1698 my $res = scsi_inquiry
($fh, 1);
1704 sub machine_type_is_q35
{
1707 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1710 sub print_tabletdevice_full
{
1711 my ($conf, $arch) = @_;
1713 my $q35 = machine_type_is_q35
($conf);
1715 # we use uhci for old VMs because tablet driver was buggy in older qemu
1717 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1723 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1726 sub print_keyboarddevice_full
{
1727 my ($conf, $arch, $machine) = @_;
1729 return undef if $arch ne 'aarch64';
1731 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1734 sub print_drivedevice_full
{
1735 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1740 if ($drive->{interface
} eq 'virtio') {
1741 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1742 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1743 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1744 } elsif ($drive->{interface
} eq 'scsi') {
1746 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1747 my $unit = $drive->{index} % $maxdev;
1748 my $devicetype = 'hd';
1750 if (drive_is_cdrom
($drive)) {
1753 if ($drive->{file
} =~ m
|^/|) {
1754 $path = $drive->{file
};
1755 if (my $info = path_is_scsi
($path)) {
1756 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1757 $devicetype = 'block';
1758 } elsif ($info->{type
} == 1) { # tape
1759 $devicetype = 'generic';
1763 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1766 if($path =~ m/^iscsi\:\/\
//){
1767 $devicetype = 'generic';
1771 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1772 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1774 $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}";
1777 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1778 $device .= ",rotation_rate=1";
1781 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1782 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1783 my $controller = int($drive->{index} / $maxdev);
1784 my $unit = $drive->{index} % $maxdev;
1785 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1787 $device = "ide-$devicetype";
1788 if ($drive->{interface
} eq 'ide') {
1789 $device .= ",bus=ide.$controller,unit=$unit";
1791 $device .= ",bus=ahci$controller.$unit";
1793 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1795 if ($devicetype eq 'hd') {
1796 if (my $model = $drive->{model
}) {
1797 $model = URI
::Escape
::uri_unescape
($model);
1798 $device .= ",model=$model";
1800 if ($drive->{ssd
}) {
1801 $device .= ",rotation_rate=1";
1804 } elsif ($drive->{interface
} eq 'usb') {
1806 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1808 die "unsupported interface type";
1811 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1813 if (my $serial = $drive->{serial
}) {
1814 $serial = URI
::Escape
::uri_unescape
($serial);
1815 $device .= ",serial=$serial";
1822 sub get_initiator_name
{
1825 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1826 while (defined(my $line = <$fh>)) {
1827 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1836 sub print_drive_full
{
1837 my ($storecfg, $vmid, $drive) = @_;
1840 my $volid = $drive->{file
};
1843 if (drive_is_cdrom
($drive)) {
1844 $path = get_iso_path
($storecfg, $vmid, $volid);
1846 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1848 $path = PVE
::Storage
::path
($storecfg, $volid);
1849 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1850 $format = qemu_img_format
($scfg, $volname);
1858 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1859 foreach my $o (@qemu_drive_options) {
1860 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1863 # snapshot only accepts on|off
1864 if (defined($drive->{snapshot
})) {
1865 my $v = $drive->{snapshot
} ?
'on' : 'off';
1866 $opts .= ",snapshot=$v";
1869 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1870 my ($dir, $qmpname) = @$type;
1871 if (my $v = $drive->{"mbps$dir"}) {
1872 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1874 if (my $v = $drive->{"mbps${dir}_max"}) {
1875 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1877 if (my $v = $drive->{"bps${dir}_max_length"}) {
1878 $opts .= ",throttling.bps$qmpname-max-length=$v";
1880 if (my $v = $drive->{"iops${dir}"}) {
1881 $opts .= ",throttling.iops$qmpname=$v";
1883 if (my $v = $drive->{"iops${dir}_max"}) {
1884 $opts .= ",throttling.iops$qmpname-max=$v";
1886 if (my $v = $drive->{"iops${dir}_max_length"}) {
1887 $opts .= ",throttling.iops$qmpname-max-length=$v";
1891 $opts .= ",format=$format" if $format && !$drive->{format
};
1893 my $cache_direct = 0;
1895 if (my $cache = $drive->{cache
}) {
1896 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1897 } elsif (!drive_is_cdrom
($drive)) {
1898 $opts .= ",cache=none";
1902 # aio native works only with O_DIRECT
1903 if (!$drive->{aio
}) {
1905 $opts .= ",aio=native";
1907 $opts .= ",aio=threads";
1911 if (!drive_is_cdrom
($drive)) {
1913 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1914 $detectzeroes = 'off';
1915 } elsif ($drive->{discard
}) {
1916 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1918 # This used to be our default with discard not being specified:
1919 $detectzeroes = 'on';
1921 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1924 my $pathinfo = $path ?
"file=$path," : '';
1926 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1929 sub print_netdevice_full
{
1930 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1932 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1934 my $device = $net->{model
};
1935 if ($net->{model
} eq 'virtio') {
1936 $device = 'virtio-net-pci';
1939 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1940 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1941 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1942 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1943 my $vectors = $net->{queues
} * 2 + 2;
1944 $tmpstr .= ",vectors=$vectors,mq=on";
1946 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1948 if ($use_old_bios_files) {
1950 if ($device eq 'virtio-net-pci') {
1951 $romfile = 'pxe-virtio.rom';
1952 } elsif ($device eq 'e1000') {
1953 $romfile = 'pxe-e1000.rom';
1954 } elsif ($device eq 'ne2k') {
1955 $romfile = 'pxe-ne2k_pci.rom';
1956 } elsif ($device eq 'pcnet') {
1957 $romfile = 'pxe-pcnet.rom';
1958 } elsif ($device eq 'rtl8139') {
1959 $romfile = 'pxe-rtl8139.rom';
1961 $tmpstr .= ",romfile=$romfile" if $romfile;
1967 sub print_netdev_full
{
1968 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1971 if ($netid =~ m/^net(\d+)$/) {
1975 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1977 my $ifname = "tap${vmid}i$i";
1979 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1980 die "interface name '$ifname' is too long (max 15 character)\n"
1981 if length($ifname) >= 16;
1983 my $vhostparam = '';
1984 if (is_native
($arch)) {
1985 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1988 my $vmname = $conf->{name
} || "vm$vmid";
1991 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1993 if ($net->{bridge
}) {
1994 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1996 $netdev = "type=user,id=$netid,hostname=$vmname";
1999 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
2005 sub print_cpu_device
{
2006 my ($conf, $id) = @_;
2008 my $kvm = $conf->{kvm
} // 1;
2009 my $cpu = $kvm ?
"kvm64" : "qemu64";
2010 if (my $cputype = $conf->{cpu
}) {
2011 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
2012 or die "Cannot parse cpu description: $cputype\n";
2013 $cpu = $cpuconf->{cputype
};
2016 my $cores = $conf->{cores
} || 1;
2018 my $current_core = ($id - 1) % $cores;
2019 my $current_socket = int(($id - 1 - $current_core)/$cores);
2021 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2025 'cirrus' => 'cirrus-vga',
2027 'vmware' => 'vmware-svga',
2028 'virtio' => 'virtio-vga',
2031 sub print_vga_device
{
2032 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2034 my $type = $vga_map->{$vga->{type
}};
2035 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
2036 $type = 'virtio-gpu';
2038 my $vgamem_mb = $vga->{memory
};
2040 $type = $id ?
'qxl' : 'qxl-vga';
2042 die "no devicetype for $vga->{type}\n" if !$type;
2046 if ($vga->{type
} eq 'virtio') {
2047 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2048 $memory = ",max_hostmem=$bytes";
2050 # from https://www.spice-space.org/multiple-monitors.html
2051 $memory = ",vgamem_mb=$vga->{memory}";
2052 my $ram = $vgamem_mb * 4;
2053 my $vram = $vgamem_mb * 2;
2054 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2056 $memory = ",vgamem_mb=$vga->{memory}";
2058 } elsif ($qxlnum && $id) {
2059 $memory = ",ram_size=67108864,vram_size=33554432";
2062 my $q35 = machine_type_is_q35
($conf);
2063 my $vgaid = "vga" . ($id // '');
2066 if ($q35 && $vgaid eq 'vga') {
2067 # the first display uses pcie.0 bus on q35 machines
2068 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2070 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2073 return "$type,id=${vgaid}${memory}${pciaddr}";
2076 sub drive_is_cloudinit
{
2078 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2081 sub drive_is_cdrom
{
2082 my ($drive, $exclude_cloudinit) = @_;
2084 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2086 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2090 sub parse_number_sets
{
2093 foreach my $part (split(/;/, $set)) {
2094 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2095 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2096 push @$res, [ $1, $2 ];
2098 die "invalid range: $part\n";
2107 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2108 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2109 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2116 return undef if !$value;
2118 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2120 my @idlist = split(/;/, $res->{host
});
2121 delete $res->{host
};
2122 foreach my $id (@idlist) {
2123 if ($id =~ m/\./) { # full id 00:00.1
2124 push @{$res->{pciid
}}, {
2127 } else { # partial id 00:00
2128 $res->{pciid
} = PVE
::SysFSTools
::lspci
($id);
2134 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2138 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2143 if (!defined($res->{macaddr
})) {
2144 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2145 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2150 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2151 sub parse_ipconfig
{
2154 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2160 if ($res->{gw
} && !$res->{ip
}) {
2161 warn 'gateway specified without specifying an IP address';
2164 if ($res->{gw6
} && !$res->{ip6
}) {
2165 warn 'IPv6 gateway specified without specifying an IPv6 address';
2168 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2169 warn 'gateway specified together with DHCP';
2172 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2174 warn "IPv6 gateway specified together with $res->{ip6} address";
2178 if (!$res->{ip
} && !$res->{ip6
}) {
2179 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2188 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2191 sub add_random_macs
{
2192 my ($settings) = @_;
2194 foreach my $opt (keys %$settings) {
2195 next if $opt !~ m/^net(\d+)$/;
2196 my $net = parse_net
($settings->{$opt});
2198 $settings->{$opt} = print_net
($net);
2202 sub vm_is_volid_owner
{
2203 my ($storecfg, $vmid, $volid) = @_;
2205 if ($volid !~ m
|^/|) {
2207 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2208 if ($owner && ($owner == $vmid)) {
2216 sub split_flagged_list
{
2217 my $text = shift || '';
2218 $text =~ s/[,;]/ /g;
2220 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2223 sub join_flagged_list
{
2224 my ($how, $lst) = @_;
2225 join $how, map { $lst->{$_} . $_ } keys %$lst;
2228 sub vmconfig_delete_pending_option
{
2229 my ($conf, $key, $force) = @_;
2231 delete $conf->{pending
}->{$key};
2232 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2233 $pending_delete_hash->{$key} = $force ?
'!' : '';
2234 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2237 sub vmconfig_undelete_pending_option
{
2238 my ($conf, $key) = @_;
2240 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2241 delete $pending_delete_hash->{$key};
2243 if (%$pending_delete_hash) {
2244 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2246 delete $conf->{pending
}->{delete};
2250 sub vmconfig_register_unused_drive
{
2251 my ($storecfg, $vmid, $conf, $drive) = @_;
2253 if (drive_is_cloudinit
($drive)) {
2254 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2256 } elsif (!drive_is_cdrom
($drive)) {
2257 my $volid = $drive->{file
};
2258 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2259 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2264 sub vmconfig_cleanup_pending
{
2267 # remove pending changes when nothing changed
2269 foreach my $opt (keys %{$conf->{pending
}}) {
2270 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2272 delete $conf->{pending
}->{$opt};
2276 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2277 my $pending_delete_hash = {};
2278 while (my ($opt, $force) = each %$current_delete_hash) {
2279 if (defined($conf->{$opt})) {
2280 $pending_delete_hash->{$opt} = $force;
2286 if (%$pending_delete_hash) {
2287 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2289 delete $conf->{pending
}->{delete};
2295 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2299 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2300 format_description
=> 'UUID',
2301 description
=> "Set SMBIOS1 UUID.",
2307 format_description
=> 'string',
2308 description
=> "Set SMBIOS1 version.",
2314 format_description
=> 'string',
2315 description
=> "Set SMBIOS1 serial number.",
2321 format_description
=> 'string',
2322 description
=> "Set SMBIOS1 manufacturer.",
2328 format_description
=> 'string',
2329 description
=> "Set SMBIOS1 product ID.",
2335 format_description
=> 'string',
2336 description
=> "Set SMBIOS1 SKU string.",
2342 format_description
=> 'string',
2343 description
=> "Set SMBIOS1 family string.",
2351 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2358 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2361 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2363 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2364 sub verify_bootdisk
{
2365 my ($value, $noerr) = @_;
2367 return $value if is_valid_drivename
($value);
2369 return undef if $noerr;
2371 die "invalid boot disk '$value'\n";
2374 sub parse_watchdog
{
2377 return undef if !$value;
2379 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2384 sub parse_guest_agent
{
2387 return {} if !defined($value->{agent
});
2389 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2392 # if the agent is disabled ignore the other potentially set properties
2393 return {} if !$res->{enabled
};
2400 return {} if !$value;
2401 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2406 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2407 sub verify_usb_device
{
2408 my ($value, $noerr) = @_;
2410 return $value if parse_usb_device
($value);
2412 return undef if $noerr;
2414 die "unable to parse usb device\n";
2417 # add JSON properties for create and set function
2418 sub json_config_properties
{
2421 foreach my $opt (keys %$confdesc) {
2422 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2423 $prop->{$opt} = $confdesc->{$opt};
2429 # return copy of $confdesc_cloudinit to generate documentation
2430 sub cloudinit_config_properties
{
2432 return dclone
($confdesc_cloudinit);
2436 my ($key, $value) = @_;
2438 die "unknown setting '$key'\n" if !$confdesc->{$key};
2440 my $type = $confdesc->{$key}->{type
};
2442 if (!defined($value)) {
2443 die "got undefined value\n";
2446 if ($value =~ m/[\n\r]/) {
2447 die "property contains a line feed\n";
2450 if ($type eq 'boolean') {
2451 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2452 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2453 die "type check ('boolean') failed - got '$value'\n";
2454 } elsif ($type eq 'integer') {
2455 return int($1) if $value =~ m/^(\d+)$/;
2456 die "type check ('integer') failed - got '$value'\n";
2457 } elsif ($type eq 'number') {
2458 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2459 die "type check ('number') failed - got '$value'\n";
2460 } elsif ($type eq 'string') {
2461 if (my $fmt = $confdesc->{$key}->{format
}) {
2462 PVE
::JSONSchema
::check_format
($fmt, $value);
2465 $value =~ s/^\"(.*)\"$/$1/;
2468 die "internal error"
2475 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2476 utime undef, undef, $conf;
2480 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2482 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2484 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2486 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2488 if ($conf->{template
}) {
2489 # check if any base image is still used by a linked clone
2490 foreach_drive
($conf, sub {
2491 my ($ds, $drive) = @_;
2493 return if drive_is_cdrom
($drive);
2495 my $volid = $drive->{file
};
2497 return if !$volid || $volid =~ m
|^/|;
2499 die "base volume '$volid' is still in use by linked cloned\n"
2500 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2505 # only remove disks owned by this VM
2506 foreach_drive
($conf, sub {
2507 my ($ds, $drive) = @_;
2509 return if drive_is_cdrom
($drive, 1);
2511 my $volid = $drive->{file
};
2513 return if !$volid || $volid =~ m
|^/|;
2515 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2516 return if !$path || !$owner || ($owner != $vmid);
2519 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2521 warn "Could not remove disk '$volid', check manually: $@" if $@;
2525 if ($keep_empty_config) {
2526 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2531 # also remove unused disk
2533 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2536 PVE
::Storage
::foreach_volid
($dl, sub {
2537 my ($volid, $sid, $volname, $d) = @_;
2538 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2547 sub parse_vm_config
{
2548 my ($filename, $raw) = @_;
2550 return undef if !defined($raw);
2553 digest
=> Digest
::SHA
::sha1_hex
($raw),
2558 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2559 || die "got strange filename '$filename'";
2567 my @lines = split(/\n/, $raw);
2568 foreach my $line (@lines) {
2569 next if $line =~ m/^\s*$/;
2571 if ($line =~ m/^\[PENDING\]\s*$/i) {
2572 $section = 'pending';
2573 if (defined($descr)) {
2575 $conf->{description
} = $descr;
2578 $conf = $res->{$section} = {};
2581 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2583 if (defined($descr)) {
2585 $conf->{description
} = $descr;
2588 $conf = $res->{snapshots
}->{$section} = {};
2592 if ($line =~ m/^\#(.*)\s*$/) {
2593 $descr = '' if !defined($descr);
2594 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2598 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2599 $descr = '' if !defined($descr);
2600 $descr .= PVE
::Tools
::decode_text
($2);
2601 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2602 $conf->{snapstate
} = $1;
2603 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2606 $conf->{$key} = $value;
2607 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2609 if ($section eq 'pending') {
2610 $conf->{delete} = $value; # we parse this later
2612 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2614 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2617 eval { $value = check_type
($key, $value); };
2619 warn "vm $vmid - unable to parse value of '$key' - $@";
2621 $key = 'ide2' if $key eq 'cdrom';
2622 my $fmt = $confdesc->{$key}->{format
};
2623 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2624 my $v = parse_drive
($key, $value);
2625 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2626 $v->{file
} = $volid;
2627 $value = print_drive
($vmid, $v);
2629 warn "vm $vmid - unable to parse value of '$key'\n";
2634 $conf->{$key} = $value;
2639 if (defined($descr)) {
2641 $conf->{description
} = $descr;
2643 delete $res->{snapstate
}; # just to be sure
2648 sub write_vm_config
{
2649 my ($filename, $conf) = @_;
2651 delete $conf->{snapstate
}; # just to be sure
2653 if ($conf->{cdrom
}) {
2654 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2655 $conf->{ide2
} = $conf->{cdrom
};
2656 delete $conf->{cdrom
};
2659 # we do not use 'smp' any longer
2660 if ($conf->{sockets
}) {
2661 delete $conf->{smp
};
2662 } elsif ($conf->{smp
}) {
2663 $conf->{sockets
} = $conf->{smp
};
2664 delete $conf->{cores
};
2665 delete $conf->{smp
};
2668 my $used_volids = {};
2670 my $cleanup_config = sub {
2671 my ($cref, $pending, $snapname) = @_;
2673 foreach my $key (keys %$cref) {
2674 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2675 $key eq 'snapstate' || $key eq 'pending';
2676 my $value = $cref->{$key};
2677 if ($key eq 'delete') {
2678 die "propertry 'delete' is only allowed in [PENDING]\n"
2680 # fixme: check syntax?
2683 eval { $value = check_type
($key, $value); };
2684 die "unable to parse value of '$key' - $@" if $@;
2686 $cref->{$key} = $value;
2688 if (!$snapname && is_valid_drivename
($key)) {
2689 my $drive = parse_drive
($key, $value);
2690 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2695 &$cleanup_config($conf);
2697 &$cleanup_config($conf->{pending
}, 1);
2699 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2700 die "internal error" if $snapname eq 'pending';
2701 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2704 # remove 'unusedX' settings if we re-add a volume
2705 foreach my $key (keys %$conf) {
2706 my $value = $conf->{$key};
2707 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2708 delete $conf->{$key};
2712 my $generate_raw_config = sub {
2713 my ($conf, $pending) = @_;
2717 # add description as comment to top of file
2718 if (defined(my $descr = $conf->{description
})) {
2720 foreach my $cl (split(/\n/, $descr)) {
2721 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2724 $raw .= "#\n" if $pending;
2728 foreach my $key (sort keys %$conf) {
2729 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2730 $raw .= "$key: $conf->{$key}\n";
2735 my $raw = &$generate_raw_config($conf);
2737 if (scalar(keys %{$conf->{pending
}})){
2738 $raw .= "\n[PENDING]\n";
2739 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2742 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2743 $raw .= "\n[$snapname]\n";
2744 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2754 # we use static defaults from our JSON schema configuration
2755 foreach my $key (keys %$confdesc) {
2756 if (defined(my $default = $confdesc->{$key}->{default})) {
2757 $res->{$key} = $default;
2765 my $vmlist = PVE
::Cluster
::get_vmlist
();
2767 return $res if !$vmlist || !$vmlist->{ids
};
2768 my $ids = $vmlist->{ids
};
2770 foreach my $vmid (keys %$ids) {
2771 my $d = $ids->{$vmid};
2772 next if !$d->{node
} || $d->{node
} ne $nodename;
2773 next if !$d->{type
} || $d->{type
} ne 'qemu';
2774 $res->{$vmid}->{exists} = 1;
2779 # test if VM uses local resources (to prevent migration)
2780 sub check_local_resources
{
2781 my ($conf, $noerr) = @_;
2785 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2786 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2788 foreach my $k (keys %$conf) {
2789 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2790 # sockets are safe: they will recreated be on the target side post-migrate
2791 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2792 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2795 die "VM uses local resources\n" if $loc_res && !$noerr;
2800 # check if used storages are available on all nodes (use by migrate)
2801 sub check_storage_availability
{
2802 my ($storecfg, $conf, $node) = @_;
2804 foreach_drive
($conf, sub {
2805 my ($ds, $drive) = @_;
2807 my $volid = $drive->{file
};
2810 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2813 # check if storage is available on both nodes
2814 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2815 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2819 # list nodes where all VM images are available (used by has_feature API)
2821 my ($conf, $storecfg) = @_;
2823 my $nodelist = PVE
::Cluster
::get_nodelist
();
2824 my $nodehash = { map { $_ => 1 } @$nodelist };
2825 my $nodename = PVE
::INotify
::nodename
();
2827 foreach_drive
($conf, sub {
2828 my ($ds, $drive) = @_;
2830 my $volid = $drive->{file
};
2833 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2835 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2836 if ($scfg->{disable
}) {
2838 } elsif (my $avail = $scfg->{nodes
}) {
2839 foreach my $node (keys %$nodehash) {
2840 delete $nodehash->{$node} if !$avail->{$node};
2842 } elsif (!$scfg->{shared
}) {
2843 foreach my $node (keys %$nodehash) {
2844 delete $nodehash->{$node} if $node ne $nodename
2854 my ($pidfile, $pid) = @_;
2856 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2860 return undef if !$line;
2861 my @param = split(/\0/, $line);
2863 my $cmd = $param[0];
2864 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2866 for (my $i = 0; $i < scalar (@param); $i++) {
2869 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2870 my $p = $param[$i+1];
2871 return 1 if $p && ($p eq $pidfile);
2880 my ($vmid, $nocheck, $node) = @_;
2882 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2884 die "unable to find configuration file for VM $vmid - no such machine\n"
2885 if !$nocheck && ! -f
$filename;
2887 my $pidfile = pidfile_name
($vmid);
2889 if (my $fd = IO
::File-
>new("<$pidfile")) {
2894 my $mtime = $st->mtime;
2895 if ($mtime > time()) {
2896 warn "file '$filename' modified in future\n";
2899 if ($line =~ m/^(\d+)$/) {
2901 if (check_cmdline
($pidfile, $pid)) {
2902 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2914 my $vzlist = config_list
();
2916 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2918 while (defined(my $de = $fd->read)) {
2919 next if $de !~ m/^(\d+)\.pid$/;
2921 next if !defined($vzlist->{$vmid});
2922 if (my $pid = check_running
($vmid)) {
2923 $vzlist->{$vmid}->{pid
} = $pid;
2931 my ($storecfg, $conf) = @_;
2933 my $bootdisk = $conf->{bootdisk
};
2934 return undef if !$bootdisk;
2935 return undef if !is_valid_drivename
($bootdisk);
2937 return undef if !$conf->{$bootdisk};
2939 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2940 return undef if !defined($drive);
2942 return undef if drive_is_cdrom
($drive);
2944 my $volid = $drive->{file
};
2945 return undef if !$volid;
2947 return $drive->{size
};
2950 our $vmstatus_return_properties = {
2951 vmid
=> get_standard_option
('pve-vmid'),
2953 description
=> "Qemu process status.",
2955 enum
=> ['stopped', 'running'],
2958 description
=> "Maximum memory in bytes.",
2961 renderer
=> 'bytes',
2964 description
=> "Root disk size in bytes.",
2967 renderer
=> 'bytes',
2970 description
=> "VM name.",
2975 description
=> "Qemu QMP agent status.",
2980 description
=> "PID of running qemu process.",
2985 description
=> "Uptime.",
2988 renderer
=> 'duration',
2991 description
=> "Maximum usable CPUs.",
2997 my $last_proc_pid_stat;
2999 # get VM status information
3000 # This must be fast and should not block ($full == false)
3001 # We only query KVM using QMP if $full == true (this can be slow)
3003 my ($opt_vmid, $full) = @_;
3007 my $storecfg = PVE
::Storage
::config
();
3009 my $list = vzlist
();
3010 my $defaults = load_defaults
();
3012 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3014 my $cpucount = $cpuinfo->{cpus
} || 1;
3016 foreach my $vmid (keys %$list) {
3017 next if $opt_vmid && ($vmid ne $opt_vmid);
3019 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3020 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3022 my $d = { vmid
=> $vmid };
3023 $d->{pid
} = $list->{$vmid}->{pid
};
3025 # fixme: better status?
3026 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3028 my $size = disksize
($storecfg, $conf);
3029 if (defined($size)) {
3030 $d->{disk
} = 0; # no info available
3031 $d->{maxdisk
} = $size;
3037 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3038 * ($conf->{cores
} || $defaults->{cores
});
3039 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3040 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3042 $d->{name
} = $conf->{name
} || "VM $vmid";
3043 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3044 : $defaults->{memory
}*(1024*1024);
3046 if ($conf->{balloon
}) {
3047 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3048 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3049 : $defaults->{shares
};
3060 $d->{diskwrite
} = 0;
3062 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3064 $d->{serial
} = 1 if conf_has_serial
($conf);
3069 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3070 foreach my $dev (keys %$netdev) {
3071 next if $dev !~ m/^tap([1-9]\d*)i/;
3073 my $d = $res->{$vmid};
3076 $d->{netout
} += $netdev->{$dev}->{receive
};
3077 $d->{netin
} += $netdev->{$dev}->{transmit
};
3080 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3081 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3086 my $ctime = gettimeofday
;
3088 foreach my $vmid (keys %$list) {
3090 my $d = $res->{$vmid};
3091 my $pid = $d->{pid
};
3094 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3095 next if !$pstat; # not running
3097 my $used = $pstat->{utime} + $pstat->{stime
};
3099 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3101 if ($pstat->{vsize
}) {
3102 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3105 my $old = $last_proc_pid_stat->{$pid};
3107 $last_proc_pid_stat->{$pid} = {
3115 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3117 if ($dtime > 1000) {
3118 my $dutime = $used - $old->{used
};
3120 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3121 $last_proc_pid_stat->{$pid} = {
3127 $d->{cpu
} = $old->{cpu
};
3131 return $res if !$full;
3133 my $qmpclient = PVE
::QMPClient-
>new();
3135 my $ballooncb = sub {
3136 my ($vmid, $resp) = @_;
3138 my $info = $resp->{'return'};
3139 return if !$info->{max_mem
};
3141 my $d = $res->{$vmid};
3143 # use memory assigned to VM
3144 $d->{maxmem
} = $info->{max_mem
};
3145 $d->{balloon
} = $info->{actual
};
3147 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3148 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3149 $d->{freemem
} = $info->{free_mem
};
3152 $d->{ballooninfo
} = $info;
3155 my $blockstatscb = sub {
3156 my ($vmid, $resp) = @_;
3157 my $data = $resp->{'return'} || [];
3158 my $totalrdbytes = 0;
3159 my $totalwrbytes = 0;
3161 for my $blockstat (@$data) {
3162 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3163 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3165 $blockstat->{device
} =~ s/drive-//;
3166 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3168 $res->{$vmid}->{diskread
} = $totalrdbytes;
3169 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3172 my $statuscb = sub {
3173 my ($vmid, $resp) = @_;
3175 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3176 # this fails if ballon driver is not loaded, so this must be
3177 # the last commnand (following command are aborted if this fails).
3178 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3180 my $status = 'unknown';
3181 if (!defined($status = $resp->{'return'}->{status
})) {
3182 warn "unable to get VM status\n";
3186 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3189 foreach my $vmid (keys %$list) {
3190 next if $opt_vmid && ($vmid ne $opt_vmid);
3191 next if !$res->{$vmid}->{pid
}; # not running
3192 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3195 $qmpclient->queue_execute(undef, 2);
3197 foreach my $vmid (keys %$list) {
3198 next if $opt_vmid && ($vmid ne $opt_vmid);
3199 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3206 my ($conf, $func, @param) = @_;
3208 foreach my $ds (valid_drive_names
()) {
3209 next if !defined($conf->{$ds});
3211 my $drive = parse_drive
($ds, $conf->{$ds});
3214 &$func($ds, $drive, @param);
3219 my ($conf, $func, @param) = @_;
3223 my $test_volid = sub {
3224 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3228 $volhash->{$volid}->{cdrom
} //= 1;
3229 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3231 $volhash->{$volid}->{replicate
} //= 0;
3232 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3234 $volhash->{$volid}->{shared
} //= 0;
3235 $volhash->{$volid}->{shared
} = 1 if $shared;
3237 $volhash->{$volid}->{referenced_in_config
} //= 0;
3238 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3240 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3241 if defined($snapname);
3244 foreach_drive
($conf, sub {
3245 my ($ds, $drive) = @_;
3246 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3249 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3250 my $snap = $conf->{snapshots
}->{$snapname};
3251 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3252 foreach_drive
($snap, sub {
3253 my ($ds, $drive) = @_;
3254 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3258 foreach my $volid (keys %$volhash) {
3259 &$func($volid, $volhash->{$volid}, @param);
3263 sub conf_has_serial
{
3266 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3267 if ($conf->{"serial$i"}) {
3275 sub vga_conf_has_spice
{
3278 my $vgaconf = parse_vga
($vga);
3279 my $vgatype = $vgaconf->{type
};
3280 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3285 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3286 sub get_host_arch
() {
3287 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3293 return get_host_arch
() eq $arch;
3296 my $default_machines = {
3301 sub get_basic_machine_info
{
3302 my ($conf, $forcemachine) = @_;
3304 my $arch = $conf->{arch
} // get_host_arch
();
3305 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3306 return ($arch, $machine);
3309 sub get_ovmf_files
($) {
3312 my $ovmf = $OVMF->{$arch}
3313 or die "no OVMF images known for architecture '$arch'\n";
3319 aarch64
=> '/usr/bin/qemu-system-aarch64',
3320 x86_64
=> '/usr/bin/qemu-system-x86_64',
3322 sub get_command_for_arch
($) {
3324 return '/usr/bin/kvm' if is_native
($arch);
3326 my $cmd = $Arch2Qemu->{$arch}
3327 or die "don't know how to emulate architecture '$arch'\n";
3331 sub get_cpu_options
{
3332 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3335 my $ostype = $conf->{ostype
};
3337 my $cpu = $kvm ?
"kvm64" : "qemu64";
3338 if ($arch eq 'aarch64') {
3339 $cpu = 'cortex-a57';
3342 if (my $cputype = $conf->{cpu
}) {
3343 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3344 or die "Cannot parse cpu description: $cputype\n";
3345 $cpu = $cpuconf->{cputype
};
3346 $kvm_off = 1 if $cpuconf->{hidden
};
3347 $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
3349 if (defined(my $flags = $cpuconf->{flags
})) {
3350 push @$cpuFlags, split(";", $flags);
3354 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3356 push @$cpuFlags , '-x2apic'
3357 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3359 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3361 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3363 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3365 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3366 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3369 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough, $hv_vendor_id) if $kvm;
3371 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3373 push @$cpuFlags, 'kvm=off' if $kvm_off;
3375 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3376 push @$cpuFlags, "vendor=${cpu_vendor}"
3377 if $cpu_vendor ne 'default';
3378 } elsif ($arch ne 'aarch64') {
3379 die "internal error"; # should not happen
3382 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3384 return ('-cpu', $cpu);
3387 sub config_to_command
{
3388 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3391 my $globalFlags = [];
3392 my $machineFlags = [];
3397 my $kvmver = kvm_user_version
();
3398 my $vernum = 0; # unknown
3399 my $ostype = $conf->{ostype
};
3400 my $winversion = windows_version
($ostype);
3401 my $kvm = $conf->{kvm
};
3403 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3404 $kvm //= 1 if is_native
($arch);
3407 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3408 if !defined kvm_version
();
3411 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3412 $vernum = $1*1000000+$2*1000;
3413 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3414 $vernum = $1*1000000+$2*1000+$3;
3417 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3419 my $have_ovz = -f
'/proc/vz/vestat';
3421 my $q35 = machine_type_is_q35
($conf);
3422 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3423 my $use_old_bios_files = undef;
3424 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3426 my $cpuunits = defined($conf->{cpuunits
}) ?
3427 $conf->{cpuunits
} : $defaults->{cpuunits
};
3429 push @$cmd, get_command_for_arch
($arch);
3431 push @$cmd, '-id', $vmid;
3433 my $vmname = $conf->{name
} || "vm$vmid";
3435 push @$cmd, '-name', $vmname;
3439 my $qmpsocket = qmp_socket
($vmid);
3440 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3441 push @$cmd, '-mon', "chardev=qmp,mode=control";
3443 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3444 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3445 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3448 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3450 push @$cmd, '-daemonize';
3452 if ($conf->{smbios1
}) {
3453 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3456 if ($conf->{vmgenid
}) {
3457 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3460 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3461 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3462 die "uefi base image not found\n" if ! -f
$ovmf_code;
3466 if (my $efidisk = $conf->{efidisk0
}) {
3467 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3468 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3469 $format = $d->{format
};
3471 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3472 if (!defined($format)) {
3473 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3474 $format = qemu_img_format
($scfg, $volname);
3478 die "efidisk format must be specified\n"
3479 if !defined($format);
3482 warn "no efidisk configured! Using temporary efivars disk.\n";
3483 $path = "/tmp/$vmid-ovmf.fd";
3484 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3488 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3489 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3493 # add usb controllers
3494 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3495 push @$devices, @usbcontrollers if @usbcontrollers;
3496 my $vga = parse_vga
($conf->{vga
});
3498 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3499 $vga->{type
} = 'qxl' if $qxlnum;
3501 if (!$vga->{type
}) {
3502 if ($arch eq 'aarch64') {
3503 $vga->{type
} = 'virtio';
3504 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3505 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3507 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3511 # enable absolute mouse coordinates (needed by vnc)
3513 if (defined($conf->{tablet
})) {
3514 $tablet = $conf->{tablet
};
3516 $tablet = $defaults->{tablet
};
3517 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3518 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3522 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3523 my $kbd = print_keyboarddevice_full
($conf, $arch);
3524 push @$devices, '-device', $kbd if defined($kbd);
3528 my $gpu_passthrough;
3531 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3532 my $d = parse_hostpci
($conf->{"hostpci$i"});
3535 my $pcie = $d->{pcie
};
3537 die "q35 machine model is not enabled" if !$q35;
3538 # win7 wants to have the pcie devices directly on the pcie bus
3539 # instead of in the root port
3540 if ($winversion == 7) {
3541 $pciaddr = print_pcie_addr
("hostpci${i}bus0");
3543 $pciaddr = print_pcie_addr
("hostpci$i");
3546 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3549 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3550 my $romfile = $d->{romfile
};
3553 if ($d->{'x-vga'}) {
3554 $xvga = ',x-vga=on';
3556 $vga->{type
} = 'none' if !defined($conf->{vga
});
3557 $gpu_passthrough = 1;
3559 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3563 my $pcidevices = $d->{pciid
};
3564 my $multifunction = 1 if @$pcidevices > 1;
3566 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3567 my $id = $pcidevices->[0]->{id
};
3568 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3569 $sysfspath = "/sys/bus/pci/devices/0000:$id/$uuid";
3570 } elsif ($d->{mdev
}) {
3571 warn "ignoring mediated device with multifunction device\n";
3575 foreach my $pcidevice (@$pcidevices) {
3577 my $id = "hostpci$i";
3578 $id .= ".$j" if $multifunction;
3579 my $addr = $pciaddr;
3580 $addr .= ".$j" if $multifunction;
3581 my $devicestr = "vfio-pci";
3583 $devicestr .= ",sysfsdev=$sysfspath";
3585 $devicestr .= ",host=$pcidevice->{id}";
3587 $devicestr .= ",id=$id$addr";
3590 $devicestr .= "$rombar$xvga";
3591 $devicestr .= ",multifunction=on" if $multifunction;
3592 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3595 push @$devices, '-device', $devicestr;
3601 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3602 push @$devices, @usbdevices if @usbdevices;
3604 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3605 if (my $path = $conf->{"serial$i"}) {
3606 if ($path eq 'socket') {
3607 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3608 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3609 # On aarch64, serial0 is the UART device. Qemu only allows
3610 # connecting UART devices via the '-serial' command line, as
3611 # the device has a fixed slot on the hardware...
3612 if ($arch eq 'aarch64' && $i == 0) {
3613 push @$devices, '-serial', "chardev:serial$i";
3615 push @$devices, '-device', "isa-serial,chardev=serial$i";
3618 die "no such serial device\n" if ! -c
$path;
3619 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3620 push @$devices, '-device', "isa-serial,chardev=serial$i";
3626 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3627 if (my $path = $conf->{"parallel$i"}) {
3628 die "no such parallel device\n" if ! -c
$path;
3629 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3630 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3631 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3637 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3638 $sockets = $conf->{sockets
} if $conf->{sockets
};
3640 my $cores = $conf->{cores
} || 1;
3642 my $maxcpus = $sockets * $cores;
3644 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3646 my $allowed_vcpus = $cpuinfo->{cpus
};
3648 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3649 if ($allowed_vcpus < $maxcpus);
3651 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3653 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3654 for (my $i = 2; $i <= $vcpus; $i++) {
3655 my $cpustr = print_cpu_device
($conf,$i);
3656 push @$cmd, '-device', $cpustr;
3661 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3663 push @$cmd, '-nodefaults';
3665 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3667 my $bootindex_hash = {};
3669 foreach my $o (split(//, $bootorder)) {
3670 $bootindex_hash->{$o} = $i*100;
3674 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3676 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3678 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3680 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3681 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3682 my $socket = vnc_socket
($vmid);
3683 push @$cmd, '-vnc', "unix:$socket,x509,password";
3685 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3686 push @$cmd, '-nographic';
3690 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3692 my $useLocaltime = $conf->{localtime};
3694 if ($winversion >= 5) { # windows
3695 $useLocaltime = 1 if !defined($conf->{localtime});
3697 # use time drift fix when acpi is enabled
3698 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3699 $tdf = 1 if !defined($conf->{tdf
});
3703 if ($winversion >= 6) {
3704 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3705 push @$cmd, '-no-hpet';
3708 push @$rtcFlags, 'driftfix=slew' if $tdf;
3711 push @$machineFlags, 'accel=tcg';
3714 if ($machine_type) {
3715 push @$machineFlags, "type=${machine_type}";
3718 if ($conf->{startdate
}) {
3719 push @$rtcFlags, "base=$conf->{startdate}";
3720 } elsif ($useLocaltime) {
3721 push @$rtcFlags, 'base=localtime';
3724 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3726 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3728 push @$cmd, '-S' if $conf->{freeze
};
3730 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3733 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3734 #push @$cmd, '-soundhw', 'es1370';
3735 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3737 if (parse_guest_agent
($conf)->{enabled
}) {
3738 my $qgasocket = qmp_socket
($vmid, 1);
3739 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3740 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3741 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3742 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3750 for(my $i = 1; $i < $qxlnum; $i++){
3751 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3754 # assume other OS works like Linux
3755 my ($ram, $vram) = ("134217728", "67108864");
3756 if ($vga->{memory
}) {
3757 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3758 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3760 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3761 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3765 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3767 my $nodename = PVE
::INotify
::nodename
();
3768 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3769 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3770 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3771 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3772 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3774 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3776 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3777 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3778 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3781 # enable balloon by default, unless explicitly disabled
3782 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3783 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3784 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3787 if ($conf->{watchdog
}) {
3788 my $wdopts = parse_watchdog
($conf->{watchdog
});
3789 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3790 my $watchdog = $wdopts->{model
} || 'i6300esb';
3791 push @$devices, '-device', "$watchdog$pciaddr";
3792 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3796 my $scsicontroller = {};
3797 my $ahcicontroller = {};
3798 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3800 # Add iscsi initiator name if available
3801 if (my $initiator = get_initiator_name
()) {
3802 push @$devices, '-iscsi', "initiator-name=$initiator";
3805 foreach_drive
($conf, sub {
3806 my ($ds, $drive) = @_;
3808 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3809 push @$vollist, $drive->{file
};
3812 # ignore efidisk here, already added in bios/fw handling code above
3813 return if $drive->{interface
} eq 'efidisk';
3815 $use_virtio = 1 if $ds =~ m/^virtio/;
3817 if (drive_is_cdrom
($drive)) {
3818 if ($bootindex_hash->{d
}) {
3819 $drive->{bootindex
} = $bootindex_hash->{d
};
3820 $bootindex_hash->{d
} += 1;
3823 if ($bootindex_hash->{c
}) {
3824 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3825 $bootindex_hash->{c
} += 1;
3829 if($drive->{interface
} eq 'virtio'){
3830 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3833 if ($drive->{interface
} eq 'scsi') {
3835 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3837 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3838 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3841 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3842 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3843 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3844 } elsif ($drive->{iothread
}) {
3845 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3849 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3850 $queues = ",num_queues=$drive->{queues}";
3853 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3854 $scsicontroller->{$controller}=1;
3857 if ($drive->{interface
} eq 'sata') {
3858 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3859 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3860 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3861 $ahcicontroller->{$controller}=1;
3864 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3865 push @$devices, '-drive',$drive_cmd;
3866 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3869 for (my $i = 0; $i < $MAX_NETS; $i++) {
3870 next if !$conf->{"net$i"};
3871 my $d = parse_net
($conf->{"net$i"});
3874 $use_virtio = 1 if $d->{model
} eq 'virtio';
3876 if ($bootindex_hash->{n
}) {
3877 $d->{bootindex
} = $bootindex_hash->{n
};
3878 $bootindex_hash->{n
} += 1;
3881 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3882 push @$devices, '-netdev', $netdevfull;
3884 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3885 push @$devices, '-device', $netdevicefull;
3890 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3895 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3897 while (my ($k, $v) = each %$bridges) {
3898 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3899 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3903 push @$cmd, @$devices;
3904 push @$cmd, '-rtc', join(',', @$rtcFlags)
3905 if scalar(@$rtcFlags);
3906 push @$cmd, '-machine', join(',', @$machineFlags)
3907 if scalar(@$machineFlags);
3908 push @$cmd, '-global', join(',', @$globalFlags)
3909 if scalar(@$globalFlags);
3912 if ($conf->{args
}) {
3913 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3917 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3922 return "${var_run_tmpdir}/$vmid.vnc";
3928 my $res = vm_mon_cmd
($vmid, 'query-spice');
3930 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3934 my ($vmid, $qga, $name) = @_;
3935 my $sockettype = $qga ?
'qga' : 'qmp';
3936 my $ext = $name ?
'-'.$name : '';
3937 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3942 return "${var_run_tmpdir}/$vmid.pid";
3945 sub vm_devices_list
{
3948 my $res = vm_mon_cmd
($vmid, 'query-pci');
3949 my $devices_to_check = [];
3951 foreach my $pcibus (@$res) {
3952 push @$devices_to_check, @{$pcibus->{devices
}},
3955 while (@$devices_to_check) {
3957 for my $d (@$devices_to_check) {
3958 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3959 next if !$d->{'pci_bridge'};
3961 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3962 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3964 $devices_to_check = $to_check;
3967 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3968 foreach my $block (@$resblock) {
3969 if($block->{device
} =~ m/^drive-(\S+)/){
3974 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3975 foreach my $mice (@$resmice) {
3976 if ($mice->{name
} eq 'QEMU HID Tablet') {
3977 $devices->{tablet
} = 1;
3982 # for usb devices there is no query-usb
3983 # but we can iterate over the entries in
3984 # qom-list path=/machine/peripheral
3985 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3986 foreach my $per (@$resperipheral) {
3987 if ($per->{name
} =~ m/^usb\d+$/) {
3988 $devices->{$per->{name
}} = 1;
3996 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3998 my $q35 = machine_type_is_q35
($conf);
4000 my $devices_list = vm_devices_list
($vmid);
4001 return 1 if defined($devices_list->{$deviceid});
4003 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
4005 if ($deviceid eq 'tablet') {
4007 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4009 } elsif ($deviceid eq 'keyboard') {
4011 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4013 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4015 die "usb hotplug currently not reliable\n";
4016 # since we can't reliably hot unplug all added usb devices
4017 # and usb passthrough disables live migration
4018 # we disable usb hotplugging for now
4019 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
4021 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4023 qemu_iothread_add
($vmid, $deviceid, $device);
4025 qemu_driveadd
($storecfg, $vmid, $device);
4026 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4028 qemu_deviceadd
($vmid, $devicefull);
4029 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4031 eval { qemu_drivedel
($vmid, $deviceid); };
4036 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4039 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4040 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4041 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4043 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4045 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4046 qemu_iothread_add
($vmid, $deviceid, $device);
4047 $devicefull .= ",iothread=iothread-$deviceid";
4050 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4051 $devicefull .= ",num_queues=$device->{queues}";
4054 qemu_deviceadd
($vmid, $devicefull);
4055 qemu_deviceaddverify
($vmid, $deviceid);
4057 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4059 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4060 qemu_driveadd
($storecfg, $vmid, $device);
4062 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4063 eval { qemu_deviceadd
($vmid, $devicefull); };
4065 eval { qemu_drivedel
($vmid, $deviceid); };
4070 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4072 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4074 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4075 my $use_old_bios_files = undef;
4076 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4078 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4079 qemu_deviceadd
($vmid, $netdevicefull);
4080 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4082 eval { qemu_netdevdel
($vmid, $deviceid); };
4087 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4090 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4091 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4093 qemu_deviceadd
($vmid, $devicefull);
4094 qemu_deviceaddverify
($vmid, $deviceid);
4097 die "can't hotplug device '$deviceid'\n";
4103 # fixme: this should raise exceptions on error!
4104 sub vm_deviceunplug
{
4105 my ($vmid, $conf, $deviceid) = @_;
4107 my $devices_list = vm_devices_list
($vmid);
4108 return 1 if !defined($devices_list->{$deviceid});
4110 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4112 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4114 qemu_devicedel
($vmid, $deviceid);
4116 } elsif ($deviceid =~ m/^usb\d+$/) {
4118 die "usb hotplug currently not reliable\n";
4119 # when unplugging usb devices this way,
4120 # there may be remaining usb controllers/hubs
4121 # so we disable it for now
4122 qemu_devicedel
($vmid, $deviceid);
4123 qemu_devicedelverify
($vmid, $deviceid);
4125 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4127 qemu_devicedel
($vmid, $deviceid);
4128 qemu_devicedelverify
($vmid, $deviceid);
4129 qemu_drivedel
($vmid, $deviceid);
4130 qemu_iothread_del
($conf, $vmid, $deviceid);
4132 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4134 qemu_devicedel
($vmid, $deviceid);
4135 qemu_devicedelverify
($vmid, $deviceid);
4136 qemu_iothread_del
($conf, $vmid, $deviceid);
4138 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4140 qemu_devicedel
($vmid, $deviceid);
4141 qemu_drivedel
($vmid, $deviceid);
4142 qemu_deletescsihw
($conf, $vmid, $deviceid);
4144 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4146 qemu_devicedel
($vmid, $deviceid);
4147 qemu_devicedelverify
($vmid, $deviceid);
4148 qemu_netdevdel
($vmid, $deviceid);
4151 die "can't unplug device '$deviceid'\n";
4157 sub qemu_deviceadd
{
4158 my ($vmid, $devicefull) = @_;
4160 $devicefull = "driver=".$devicefull;
4161 my %options = split(/[=,]/, $devicefull);
4163 vm_mon_cmd
($vmid, "device_add" , %options);
4166 sub qemu_devicedel
{
4167 my ($vmid, $deviceid) = @_;
4169 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4172 sub qemu_iothread_add
{
4173 my($vmid, $deviceid, $device) = @_;
4175 if ($device->{iothread
}) {
4176 my $iothreads = vm_iothreads_list
($vmid);
4177 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4181 sub qemu_iothread_del
{
4182 my($conf, $vmid, $deviceid) = @_;
4184 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4185 if ($device->{iothread
}) {
4186 my $iothreads = vm_iothreads_list
($vmid);
4187 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4191 sub qemu_objectadd
{
4192 my($vmid, $objectid, $qomtype) = @_;
4194 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4199 sub qemu_objectdel
{
4200 my($vmid, $objectid) = @_;
4202 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4208 my ($storecfg, $vmid, $device) = @_;
4210 my $drive = print_drive_full
($storecfg, $vmid, $device);
4211 $drive =~ s/\\/\\\\/g;
4212 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4214 # If the command succeeds qemu prints: "OK
"
4215 return 1 if $ret =~ m/OK/s;
4217 die "adding drive failed
: $ret\n";
4221 my($vmid, $deviceid) = @_;
4223 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4226 return 1 if $ret eq "";
4228 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4229 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4231 die "deleting drive
$deviceid failed
: $ret\n";
4234 sub qemu_deviceaddverify {
4235 my ($vmid, $deviceid) = @_;
4237 for (my $i = 0; $i <= 5; $i++) {
4238 my $devices_list = vm_devices_list($vmid);
4239 return 1 if defined($devices_list->{$deviceid});
4243 die "error on hotplug device
'$deviceid'\n";
4247 sub qemu_devicedelverify {
4248 my ($vmid, $deviceid) = @_;
4250 # need to verify that the device is correctly removed as device_del
4251 # is async and empty return is not reliable
4253 for (my $i = 0; $i <= 5; $i++) {
4254 my $devices_list = vm_devices_list($vmid);
4255 return 1 if !defined($devices_list->{$deviceid});
4259 die "error on hot-unplugging device
'$deviceid'\n";
4262 sub qemu_findorcreatescsihw {
4263 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4265 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4267 my $scsihwid="$controller_prefix$controller";
4268 my $devices_list = vm_devices_list($vmid);
4270 if(!defined($devices_list->{$scsihwid})) {
4271 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4277 sub qemu_deletescsihw {
4278 my ($conf, $vmid, $opt) = @_;
4280 my $device = parse_drive($opt, $conf->{$opt});
4282 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4283 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4287 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4289 my $devices_list = vm_devices_list($vmid);
4290 foreach my $opt (keys %{$devices_list}) {
4291 if (PVE::QemuServer::is_valid_drivename($opt)) {
4292 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4293 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4299 my $scsihwid="scsihw
$controller";
4301 vm_deviceunplug($vmid, $conf, $scsihwid);
4306 sub qemu_add_pci_bridge {
4307 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4313 print_pci_addr($device, $bridges, $arch, $machine_type);
4315 while (my ($k, $v) = each %$bridges) {
4318 return 1 if !defined($bridgeid) || $bridgeid < 1;
4320 my $bridge = "pci
.$bridgeid";
4321 my $devices_list = vm_devices_list($vmid);
4323 if (!defined($devices_list->{$bridge})) {
4324 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4330 sub qemu_set_link_status {
4331 my ($vmid, $device, $up) = @_;
4333 vm_mon_cmd($vmid, "set_link
", name => $device,
4334 up => $up ? JSON::true : JSON::false);
4337 sub qemu_netdevadd {
4338 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4340 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4341 my %options = split(/[=,]/, $netdev);
4343 vm_mon_cmd($vmid, "netdev_add
", %options);
4347 sub qemu_netdevdel {
4348 my ($vmid, $deviceid) = @_;
4350 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4353 sub qemu_usb_hotplug {
4354 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4358 # remove the old one first
4359 vm_deviceunplug($vmid, $conf, $deviceid);
4361 # check if xhci controller is necessary and available
4362 if ($device->{usb3}) {
4364 my $devicelist = vm_devices_list($vmid);
4366 if (!$devicelist->{xhci}) {
4367 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4368 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4371 my $d = parse_usb_device($device->{host});
4372 $d->{usb3} = $device->{usb3};
4375 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4378 sub qemu_cpu_hotplug {
4379 my ($vmid, $conf, $vcpus) = @_;
4381 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4384 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4385 $sockets = $conf->{sockets} if $conf->{sockets};
4386 my $cores = $conf->{cores} || 1;
4387 my $maxcpus = $sockets * $cores;
4389 $vcpus = $maxcpus if !$vcpus;
4391 die "you can
't add more vcpus than maxcpus\n"
4392 if $vcpus > $maxcpus;
4394 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4396 if ($vcpus < $currentvcpus) {
4398 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4400 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4401 qemu_devicedel($vmid, "cpu$i");
4403 my $currentrunningvcpus = undef;
4405 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4406 last if scalar(@{$currentrunningvcpus}) == $i-1;
4407 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4411 #update conf after each succesfull cpu unplug
4412 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4413 PVE::QemuConfig->write_config($vmid, $conf);
4416 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4422 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4423 die "vcpus in running vm does not match its configuration\n"
4424 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4426 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4428 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4429 my $cpustr = print_cpu_device($conf, $i);
4430 qemu_deviceadd($vmid, $cpustr);
4433 my $currentrunningvcpus = undef;
4435 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4436 last if scalar(@{$currentrunningvcpus}) == $i;
4437 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4441 #update conf after each succesfull cpu hotplug
4442 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4443 PVE::QemuConfig->write_config($vmid, $conf);
4447 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4448 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4453 sub qemu_block_set_io_throttle {
4454 my ($vmid, $deviceid,
4455 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4456 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4457 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4458 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4460 return if !check_running($vmid) ;
4462 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4464 bps_rd => int($bps_rd),
4465 bps_wr => int($bps_wr),
4467 iops_rd => int($iops_rd),
4468 iops_wr => int($iops_wr),
4469 bps_max => int($bps_max),
4470 bps_rd_max => int($bps_rd_max),
4471 bps_wr_max => int($bps_wr_max),
4472 iops_max => int($iops_max),
4473 iops_rd_max => int($iops_rd_max),
4474 iops_wr_max => int($iops_wr_max),
4475 bps_max_length => int($bps_max_length),
4476 bps_rd_max_length => int($bps_rd_max_length),
4477 bps_wr_max_length => int($bps_wr_max_length),
4478 iops_max_length => int($iops_max_length),
4479 iops_rd_max_length => int($iops_rd_max_length),
4480 iops_wr_max_length => int($iops_wr_max_length),
4485 # old code, only used to shutdown old VM after update
4487 my ($fh, $timeout) = @_;
4489 my $sel = new IO::Select;
4496 while (scalar (@ready = $sel->can_read($timeout))) {
4498 if ($count = $fh->sysread($buf, 8192)) {
4499 if ($buf =~ /^(.*)\(qemu\) $/s) {
4506 if (!defined($count)) {
4513 die "monitor read timeout\n" if !scalar(@ready);
4518 sub qemu_block_resize {
4519 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4521 my $running = check_running($vmid);
4523 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4525 return if !$running;
4527 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4531 sub qemu_volume_snapshot {
4532 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4534 my $running = check_running($vmid);
4536 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4537 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4539 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4543 sub qemu_volume_snapshot_delete {
4544 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4546 my $running = check_running($vmid);
4551 my $conf = PVE::QemuConfig->load_config($vmid);
4552 foreach_drive($conf, sub {
4553 my ($ds, $drive) = @_;
4554 $running = 1 if $drive->{file} eq $volid;
4558 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4559 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4561 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4565 sub set_migration_caps {
4571 "auto-converge" => 1,
4573 "x-rdma-pin-all" => 0,
4578 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4580 for my $supported_capability (@$supported_capabilities) {
4582 capability => $supported_capability->{capability},
4583 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4587 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4590 my $fast_plug_option = {
4598 'vmstatestorage
' => 1,
4601 # hotplug changes in [PENDING]
4602 # $selection hash can be used to only apply specified options, for
4603 # example: { cores => 1 } (only apply changed 'cores
')
4604 # $errors ref is used to return error messages
4605 sub vmconfig_hotplug_pending {
4606 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4608 my $defaults = load_defaults();
4609 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4611 # commit values which do not have any impact on running VM first
4612 # Note: those option cannot raise errors, we we do not care about
4613 # $selection and always apply them.
4615 my $add_error = sub {
4616 my ($opt, $msg) = @_;
4617 $errors->{$opt} = "hotplug problem - $msg";
4621 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4622 if ($fast_plug_option->{$opt}) {
4623 $conf->{$opt} = $conf->{pending}->{$opt};
4624 delete $conf->{pending}->{$opt};
4630 PVE::QemuConfig->write_config($vmid, $conf);
4631 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4634 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4636 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4637 while (my ($opt, $force) = each %$pending_delete_hash) {
4638 next if $selection && !$selection->{$opt};
4640 if ($opt eq 'hotplug
') {
4641 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4642 } elsif ($opt eq 'tablet
') {
4643 die "skip\n" if !$hotplug_features->{usb};
4644 if ($defaults->{tablet}) {
4645 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4646 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4647 if $arch eq 'aarch64
';
4649 vm_deviceunplug($vmid, $conf, 'tablet
');
4650 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4652 } elsif ($opt =~ m/^usb\d+/) {
4654 # since we cannot reliably hot unplug usb devices
4655 # we are disabling it
4656 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4657 vm_deviceunplug($vmid, $conf, $opt);
4658 } elsif ($opt eq 'vcpus
') {
4659 die "skip\n" if !$hotplug_features->{cpu};
4660 qemu_cpu_hotplug($vmid, $conf, undef);
4661 } elsif ($opt eq 'balloon
') {
4662 # enable balloon device is not hotpluggable
4663 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4664 # here we reset the ballooning value to memory
4665 my $balloon = $conf->{memory} || $defaults->{memory};
4666 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4667 } elsif ($fast_plug_option->{$opt}) {
4669 } elsif ($opt =~ m/^net(\d+)$/) {
4670 die "skip\n" if !$hotplug_features->{network};
4671 vm_deviceunplug($vmid, $conf, $opt);
4672 } elsif (is_valid_drivename($opt)) {
4673 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4674 vm_deviceunplug($vmid, $conf, $opt);
4675 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4676 } elsif ($opt =~ m/^memory$/) {
4677 die "skip\n" if !$hotplug_features->{memory};
4678 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4679 } elsif ($opt eq 'cpuunits
') {
4680 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4681 } elsif ($opt eq 'cpulimit
') {
4682 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4688 &$add_error($opt, $err) if $err ne "skip\n";
4690 # save new config if hotplug was successful
4691 delete $conf->{$opt};
4692 vmconfig_undelete_pending_option($conf, $opt);
4693 PVE::QemuConfig->write_config($vmid, $conf);
4694 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4698 my $apply_pending_cloudinit;
4699 $apply_pending_cloudinit = sub {
4700 my ($key, $value) = @_;
4701 $apply_pending_cloudinit = sub {}; # once is enough
4703 my @cloudinit_opts = keys %$confdesc_cloudinit;
4704 foreach my $opt (keys %{$conf->{pending}}) {
4705 next if !grep { $_ eq $opt } @cloudinit_opts;
4706 $conf->{$opt} = delete $conf->{pending}->{$opt};
4709 my $new_conf = { %$conf };
4710 $new_conf->{$key} = $value;
4711 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4714 foreach my $opt (keys %{$conf->{pending}}) {
4715 next if $selection && !$selection->{$opt};
4716 my $value = $conf->{pending}->{$opt};
4718 if ($opt eq 'hotplug
') {
4719 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4720 } elsif ($opt eq 'tablet
') {
4721 die "skip\n" if !$hotplug_features->{usb};
4723 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4724 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4725 if $arch eq 'aarch64
';
4726 } elsif ($value == 0) {
4727 vm_deviceunplug($vmid, $conf, 'tablet
');
4728 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4730 } elsif ($opt =~ m/^usb\d+$/) {
4732 # since we cannot reliably hot unplug usb devices
4733 # we are disabling it
4734 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4735 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4736 die "skip\n" if !$d;
4737 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4738 } elsif ($opt eq 'vcpus
') {
4739 die "skip\n" if !$hotplug_features->{cpu};
4740 qemu_cpu_hotplug($vmid, $conf, $value);
4741 } elsif ($opt eq 'balloon
') {
4742 # enable/disable balloning device is not hotpluggable
4743 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4744 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4745 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4747 # allow manual ballooning if shares is set to zero
4748 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4749 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4750 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4752 } elsif ($opt =~ m/^net(\d+)$/) {
4753 # some changes can be done without hotplug
4754 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4755 $vmid, $opt, $value, $arch, $machine_type);
4756 } elsif (is_valid_drivename($opt)) {
4757 # some changes can be done without hotplug
4758 my $drive = parse_drive($opt, $value);
4759 if (drive_is_cloudinit($drive)) {
4760 &$apply_pending_cloudinit($opt, $value);
4762 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4763 $vmid, $opt, $value, 1, $arch, $machine_type);
4764 } elsif ($opt =~ m/^memory$/) { #dimms
4765 die "skip\n" if !$hotplug_features->{memory};
4766 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4767 } elsif ($opt eq 'cpuunits
') {
4768 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4769 } elsif ($opt eq 'cpulimit
') {
4770 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4771 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4773 die "skip\n"; # skip non-hot-pluggable options
4777 &$add_error($opt, $err) if $err ne "skip\n";
4779 # save new config if hotplug was successful
4780 $conf->{$opt} = $value;
4781 delete $conf->{pending}->{$opt};
4782 PVE::QemuConfig->write_config($vmid, $conf);
4783 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4788 sub try_deallocate_drive {
4789 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4791 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4792 my $volid = $drive->{file};
4793 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4794 my $sid = PVE::Storage::parse_volume_id($volid);
4795 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4797 # check if the disk is really unused
4798 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4799 if is_volume_in_use($storecfg, $conf, $key, $volid);
4800 PVE::Storage::vdisk_free($storecfg, $volid);
4803 # If vm is not owner of this disk remove from config
4811 sub vmconfig_delete_or_detach_drive {
4812 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4814 my $drive = parse_drive($opt, $conf->{$opt});
4816 my $rpcenv = PVE::RPCEnvironment::get();
4817 my $authuser = $rpcenv->get_user();
4820 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4821 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4823 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4827 sub vmconfig_apply_pending {
4828 my ($vmid, $conf, $storecfg) = @_;
4832 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4833 while (my ($opt, $force) = each %$pending_delete_hash) {
4834 die "internal error" if $opt =~ m/^unused/;
4835 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4836 if (!defined($conf->{$opt})) {
4837 vmconfig_undelete_pending_option($conf, $opt);
4838 PVE::QemuConfig->write_config($vmid, $conf);
4839 } elsif (is_valid_drivename($opt)) {
4840 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4841 vmconfig_undelete_pending_option($conf, $opt);
4842 delete $conf->{$opt};
4843 PVE::QemuConfig->write_config($vmid, $conf);
4845 vmconfig_undelete_pending_option($conf, $opt);
4846 delete $conf->{$opt};
4847 PVE::QemuConfig->write_config($vmid, $conf);
4851 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4853 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4854 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4856 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4857 # skip if nothing changed
4858 } elsif (is_valid_drivename($opt)) {
4859 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4860 if defined($conf->{$opt});
4861 $conf->{$opt} = $conf->{pending}->{$opt};
4863 $conf->{$opt} = $conf->{pending}->{$opt};
4866 delete $conf->{pending}->{$opt};
4867 PVE::QemuConfig->write_config($vmid, $conf);
4871 my $safe_num_ne = sub {
4874 return 0 if !defined($a) && !defined($b);
4875 return 1 if !defined($a);
4876 return 1 if !defined($b);
4881 my $safe_string_ne = sub {
4884 return 0 if !defined($a) && !defined($b);
4885 return 1 if !defined($a);
4886 return 1 if !defined($b);
4891 sub vmconfig_update_net {
4892 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4894 my $newnet = parse_net($value);
4896 if ($conf->{$opt}) {
4897 my $oldnet = parse_net($conf->{$opt});
4899 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4900 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4901 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4902 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4904 # for non online change, we try to hot-unplug
4905 die "skip\n" if !$hotplug;
4906 vm_deviceunplug($vmid, $conf, $opt);
4909 die "internal error" if $opt !~ m/net(\d+)/;
4910 my $iface = "tap${vmid}i$1";
4912 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4913 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4914 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4915 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4916 PVE::Network::tap_unplug($iface);
4917 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4918 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4919 # Rate can be applied on its own but any change above needs to
4920 # include the rate in tap_plug since OVS resets everything.
4921 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4924 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4925 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4933 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4939 sub vmconfig_update_disk {
4940 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
4942 # fixme: do we need force?
4944 my $drive = parse_drive($opt, $value);
4946 if ($conf->{$opt}) {
4948 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4950 my $media = $drive->{media} || 'disk
';
4951 my $oldmedia = $old_drive->{media} || 'disk
';
4952 die "unable to change media type\n" if $media ne $oldmedia;
4954 if (!drive_is_cdrom($old_drive)) {
4956 if ($drive->{file} ne $old_drive->{file}) {
4958 die "skip\n" if !$hotplug;
4960 # unplug and register as unused
4961 vm_deviceunplug($vmid, $conf, $opt);
4962 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4965 # update existing disk
4967 # skip non hotpluggable value
4968 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4969 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4970 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4971 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4976 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4977 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4978 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4979 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4980 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4981 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4982 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4983 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4984 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4985 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4986 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4987 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4988 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4989 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4990 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4991 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4992 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4993 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4995 qemu_block_set_io_throttle($vmid,"drive-$opt",
4996 ($drive->{mbps} || 0)*1024*1024,
4997 ($drive->{mbps_rd} || 0)*1024*1024,
4998 ($drive->{mbps_wr} || 0)*1024*1024,
4999 $drive->{iops} || 0,
5000 $drive->{iops_rd} || 0,
5001 $drive->{iops_wr} || 0,
5002 ($drive->{mbps_max} || 0)*1024*1024,
5003 ($drive->{mbps_rd_max} || 0)*1024*1024,
5004 ($drive->{mbps_wr_max} || 0)*1024*1024,
5005 $drive->{iops_max} || 0,
5006 $drive->{iops_rd_max} || 0,
5007 $drive->{iops_wr_max} || 0,
5008 $drive->{bps_max_length} || 1,
5009 $drive->{bps_rd_max_length} || 1,
5010 $drive->{bps_wr_max_length} || 1,
5011 $drive->{iops_max_length} || 1,
5012 $drive->{iops_rd_max_length} || 1,
5013 $drive->{iops_wr_max_length} || 1);
5022 if ($drive->{file} eq 'none
') {
5023 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
5024 if (drive_is_cloudinit($old_drive)) {
5025 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5028 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5029 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5030 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5038 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5040 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5041 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5045 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5046 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5048 PVE::QemuConfig->lock_config($vmid, sub {
5049 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5051 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5053 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5055 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5057 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5058 vmconfig_apply_pending($vmid, $conf, $storecfg);
5059 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5062 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5064 my $defaults = load_defaults();
5066 # set environment variable useful inside network script
5067 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5069 my $local_volumes = {};
5071 if ($targetstorage) {
5072 foreach_drive($conf, sub {
5073 my ($ds, $drive) = @_;
5075 return if drive_is_cdrom($drive);
5077 my $volid = $drive->{file};
5081 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5083 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5084 return if $scfg->{shared};
5085 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5090 foreach my $opt (sort keys %$local_volumes) {
5092 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5093 my $drive = parse_drive($opt, $conf->{$opt});
5095 #if remote storage is specified, use default format
5096 if ($targetstorage && $targetstorage ne "1") {
5097 $storeid = $targetstorage;
5098 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5099 $format = $defFormat;
5101 #else we use same format than original
5102 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5103 $format = qemu_img_format($scfg, $volid);
5106 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5107 my $newdrive = $drive;
5108 $newdrive->{format} = $format;
5109 $newdrive->{file} = $newvolid;
5110 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5111 $local_volumes->{$opt} = $drivestr;
5112 #pass drive to conf for command line
5113 $conf->{$opt} = $drivestr;
5117 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5119 my $migrate_port = 0;
5122 if ($statefile eq 'tcp
') {
5123 my $localip = "localhost";
5124 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5125 my $nodename = PVE::INotify::nodename();
5127 if (!defined($migration_type)) {
5128 if (defined($datacenterconf->{migration}->{type})) {
5129 $migration_type = $datacenterconf->{migration}->{type};
5131 $migration_type = 'secure
';
5135 if ($migration_type eq 'insecure
') {
5136 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5137 if ($migrate_network_addr) {
5138 $localip = $migrate_network_addr;
5140 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5143 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5146 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5147 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5148 $migrate_uri = "tcp:${localip}:${migrate_port}";
5149 push @$cmd, '-incoming
', $migrate_uri;
5152 } elsif ($statefile eq 'unix
') {
5153 # should be default for secure migrations as a ssh TCP forward
5154 # tunnel is not deterministic reliable ready and fails regurarly
5155 # to set up in time, so use UNIX socket forwards
5156 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5157 unlink $socket_addr;
5159 $migrate_uri = "unix:$socket_addr";
5161 push @$cmd, '-incoming
', $migrate_uri;
5165 push @$cmd, '-loadstate
', $statefile;
5172 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5173 my $d = parse_hostpci($conf->{"hostpci$i"});
5175 my $pcidevices = $d->{pciid};
5176 foreach my $pcidevice (@$pcidevices) {
5177 my $pciid = $pcidevice->{id};
5179 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5180 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5181 die "no pci device info for device '$pciid'\n" if !$info;
5184 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5185 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5187 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5188 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5189 die "can
't reset pci device '$pciid'\n"
5190 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5195 PVE::Storage::activate_volumes($storecfg, $vollist);
5197 if (!check_running($vmid, 1)) {
5199 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5200 outfunc => sub {}, errfunc => sub {});
5204 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5205 : $defaults->{cpuunits};
5207 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5208 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5211 Slice => 'qemu
.slice
',
5213 CPUShares => $cpuunits
5216 if (my $cpulimit = $conf->{cpulimit}) {
5217 $properties{CPUQuota} = int($cpulimit * 100);
5219 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5221 my $run_qemu = sub {
5222 PVE::Tools::run_fork sub {
5223 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5224 run_command($cmd, %run_params);
5228 if ($conf->{hugepages}) {
5231 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5232 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5234 PVE::QemuServer::Memory::hugepages_mount();
5235 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5237 eval { $run_qemu->() };
5239 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5243 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5245 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5248 eval { $run_qemu->() };
5252 # deactivate volumes if start fails
5253 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5254 die "start failed: $err";
5257 print "migration listens on $migrate_uri\n" if $migrate_uri;
5259 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5260 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5264 #start nbd server for storage migration
5265 if ($targetstorage) {
5266 my $nodename = PVE::INotify::nodename();
5267 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5268 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5269 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5270 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5272 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5274 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5276 foreach my $opt (sort keys %$local_volumes) {
5277 my $volid = $local_volumes->{$opt};
5278 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5279 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5280 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5284 if ($migratedfrom) {
5286 set_migration_caps($vmid);
5291 print "spice listens on port $spice_port\n";
5292 if ($spice_ticket) {
5293 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5294 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5299 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5300 if !$statefile && $conf->{balloon};
5302 foreach my $opt (keys %$conf) {
5303 next if $opt !~ m/^net\d+$/;
5304 my $nicconf = parse_net($conf->{$opt});
5305 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5309 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5310 path => "machine/peripheral/balloon0",
5311 property => "guest-stats-polling-interval",
5312 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5318 my ($vmid, $execute, %params) = @_;
5320 my $cmd = { execute => $execute, arguments => \%params };
5321 vm_qmp_command($vmid, $cmd);
5324 sub vm_mon_cmd_nocheck {
5325 my ($vmid, $execute, %params) = @_;
5327 my $cmd = { execute => $execute, arguments => \%params };
5328 vm_qmp_command($vmid, $cmd, 1);
5331 sub vm_qmp_command {
5332 my ($vmid, $cmd, $nocheck) = @_;
5337 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5338 $timeout = $cmd->{arguments}->{timeout};
5339 delete $cmd->{arguments}->{timeout};
5343 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5344 my $sname = qmp_socket($vmid);
5345 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5346 my $qmpclient = PVE::QMPClient->new();
5348 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5350 die "unable to open monitor socket\n";
5354 syslog("err", "VM $vmid qmp command failed - $err");
5361 sub vm_human_monitor_command {
5362 my ($vmid, $cmdline) = @_;
5367 execute => 'human-monitor-command
',
5368 arguments => { 'command-line
' => $cmdline},
5371 return vm_qmp_command($vmid, $cmd);
5374 sub vm_commandline {
5375 my ($storecfg, $vmid, $snapname) = @_;
5377 my $conf = PVE::QemuConfig->load_config($vmid);
5380 my $snapshot = $conf->{snapshots}->{$snapname};
5381 die "snapshot '$snapname' does not exist\n"
5382 if !defined($snapshot);
5383 my $digest = $conf->{digest};
5385 # we need the digest of the file
5386 $snapshot->{digest} = $conf->{digest};
5390 my $defaults = load_defaults();
5392 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5394 return PVE::Tools::cmd2string($cmd);
5398 my ($vmid, $skiplock) = @_;
5400 PVE::QemuConfig->lock_config($vmid, sub {
5402 my $conf = PVE::QemuConfig->load_config($vmid);
5404 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5406 vm_mon_cmd($vmid, "system_reset");
5410 sub get_vm_volumes {
5414 foreach_volid($conf, sub {
5415 my ($volid, $attr) = @_;
5417 return if $volid =~ m|^/|;
5419 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5422 push @$vollist, $volid;
5428 sub vm_stop_cleanup {
5429 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5434 my $vollist = get_vm_volumes($conf);
5435 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5438 foreach my $ext (qw(mon qmp pid vnc qga)) {
5439 unlink "/var/run/qemu-server/${vmid}.$ext";
5442 foreach my $key (keys %$conf) {
5443 next if $key !~ m/^hostpci(\d+)$/;
5444 my $hostpciindex = $1;
5445 my $d = parse_hostpci
($conf->{$key});
5446 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5448 foreach my $pci (@{$d->{pciid
}}) {
5449 my $pciid = $pci->{id
};
5450 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5454 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5456 warn $@ if $@; # avoid errors - just warn
5459 # Note: use $nockeck to skip tests if VM configuration file exists.
5460 # We need that when migration VMs to other nodes (files already moved)
5461 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5463 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5465 $force = 1 if !defined($force) && !$shutdown;
5468 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5469 kill 15, $pid if $pid;
5470 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5471 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5475 PVE
::QemuConfig-
>lock_config($vmid, sub {
5477 my $pid = check_running
($vmid, $nocheck);
5482 $conf = PVE
::QemuConfig-
>load_config($vmid);
5483 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5484 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5485 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5486 $timeout = $opts->{down
} if $opts->{down
};
5490 $timeout = 60 if !defined($timeout);
5494 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5495 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5497 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5500 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5507 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5512 if ($count >= $timeout) {
5514 warn "VM still running - terminating now with SIGTERM\n";
5517 die "VM quit/powerdown failed - got timeout\n";
5520 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5525 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5528 die "VM quit/powerdown failed\n";
5536 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5541 if ($count >= $timeout) {
5542 warn "VM still running - terminating now with SIGKILL\n";
5547 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5552 my ($vmid, $skiplock) = @_;
5554 PVE
::QemuConfig-
>lock_config($vmid, sub {
5556 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5558 PVE
::QemuConfig-
>check_lock($conf)
5559 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5561 vm_mon_cmd
($vmid, "stop");
5566 my ($vmid, $skiplock, $nocheck) = @_;
5568 PVE
::QemuConfig-
>lock_config($vmid, sub {
5570 my $res = vm_mon_cmd
($vmid, 'query-status');
5571 my $resume_cmd = 'cont';
5573 if ($res->{status
} && $res->{status
} eq 'suspended') {
5574 $resume_cmd = 'system_wakeup';
5579 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5581 PVE
::QemuConfig-
>check_lock($conf)
5582 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5584 vm_mon_cmd
($vmid, $resume_cmd);
5587 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5593 my ($vmid, $skiplock, $key) = @_;
5595 PVE
::QemuConfig-
>lock_config($vmid, sub {
5597 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5599 # there is no qmp command, so we use the human monitor command
5600 vm_human_monitor_command
($vmid, "sendkey $key");
5605 my ($storecfg, $vmid, $skiplock) = @_;
5607 PVE
::QemuConfig-
>lock_config($vmid, sub {
5609 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5611 if (!check_running
($vmid)) {
5612 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5614 die "VM $vmid is running - destroy failed\n";
5619 # vzdump restore implementaion
5621 sub tar_archive_read_firstfile
{
5622 my $archive = shift;
5624 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5626 # try to detect archive type first
5627 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5628 die "unable to open file '$archive'\n";
5629 my $firstfile = <$fh>;
5633 die "ERROR: archive contaions no data\n" if !$firstfile;
5639 sub tar_restore_cleanup
{
5640 my ($storecfg, $statfile) = @_;
5642 print STDERR
"starting cleanup\n";
5644 if (my $fd = IO
::File-
>new($statfile, "r")) {
5645 while (defined(my $line = <$fd>)) {
5646 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5649 if ($volid =~ m
|^/|) {
5650 unlink $volid || die 'unlink failed\n';
5652 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5654 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5656 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5658 print STDERR
"unable to parse line in statfile - $line";
5665 sub restore_archive
{
5666 my ($archive, $vmid, $user, $opts) = @_;
5668 my $format = $opts->{format
};
5671 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5672 $format = 'tar' if !$format;
5674 } elsif ($archive =~ m/\.tar$/) {
5675 $format = 'tar' if !$format;
5676 } elsif ($archive =~ m/.tar.lzo$/) {
5677 $format = 'tar' if !$format;
5679 } elsif ($archive =~ m/\.vma$/) {
5680 $format = 'vma' if !$format;
5681 } elsif ($archive =~ m/\.vma\.gz$/) {
5682 $format = 'vma' if !$format;
5684 } elsif ($archive =~ m/\.vma\.lzo$/) {
5685 $format = 'vma' if !$format;
5688 $format = 'vma' if !$format; # default
5691 # try to detect archive format
5692 if ($format eq 'tar') {
5693 return restore_tar_archive
($archive, $vmid, $user, $opts);
5695 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5699 sub restore_update_config_line
{
5700 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5702 return if $line =~ m/^\#qmdump\#/;
5703 return if $line =~ m/^\#vzdump\#/;
5704 return if $line =~ m/^lock:/;
5705 return if $line =~ m/^unused\d+:/;
5706 return if $line =~ m/^parent:/;
5707 return if $line =~ m/^template:/; # restored VM is never a template
5709 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5710 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5711 # try to convert old 1.X settings
5712 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5713 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5714 my ($model, $macaddr) = split(/\=/, $devconfig);
5715 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5718 bridge
=> "vmbr$ind",
5719 macaddr
=> $macaddr,
5721 my $netstr = print_net
($net);
5723 print $outfd "net$cookie->{netcount}: $netstr\n";
5724 $cookie->{netcount
}++;
5726 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5727 my ($id, $netstr) = ($1, $2);
5728 my $net = parse_net
($netstr);
5729 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5730 $netstr = print_net
($net);
5731 print $outfd "$id: $netstr\n";
5732 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5735 my $di = parse_drive
($virtdev, $value);
5736 if (defined($di->{backup
}) && !$di->{backup
}) {
5737 print $outfd "#$line";
5738 } elsif ($map->{$virtdev}) {
5739 delete $di->{format
}; # format can change on restore
5740 $di->{file
} = $map->{$virtdev};
5741 $value = print_drive
($vmid, $di);
5742 print $outfd "$virtdev: $value\n";
5746 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5748 if ($vmgenid ne '0') {
5749 # always generate a new vmgenid if there was a valid one setup
5750 $vmgenid = generate_uuid
();
5752 print $outfd "vmgenid: $vmgenid\n";
5753 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5754 my ($uuid, $uuid_str);
5755 UUID
::generate
($uuid);
5756 UUID
::unparse
($uuid, $uuid_str);
5757 my $smbios1 = parse_smbios1
($2);
5758 $smbios1->{uuid
} = $uuid_str;
5759 print $outfd $1.print_smbios1
($smbios1)."\n";
5766 my ($cfg, $vmid) = @_;
5768 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5770 my $volid_hash = {};
5771 foreach my $storeid (keys %$info) {
5772 foreach my $item (@{$info->{$storeid}}) {
5773 next if !($item->{volid
} && $item->{size
});
5774 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5775 $volid_hash->{$item->{volid
}} = $item;
5782 sub is_volume_in_use
{
5783 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5785 my $path = PVE
::Storage
::path
($storecfg, $volid);
5787 my $scan_config = sub {
5788 my ($cref, $snapname) = @_;
5790 foreach my $key (keys %$cref) {
5791 my $value = $cref->{$key};
5792 if (is_valid_drivename
($key)) {
5793 next if $skip_drive && $key eq $skip_drive;
5794 my $drive = parse_drive
($key, $value);
5795 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5796 return 1 if $volid eq $drive->{file
};
5797 if ($drive->{file
} =~ m!^/!) {
5798 return 1 if $drive->{file
} eq $path;
5800 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5802 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5804 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5812 return 1 if &$scan_config($conf);
5816 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5817 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5823 sub update_disksize
{
5824 my ($vmid, $conf, $volid_hash) = @_;
5827 my $prefix = "VM $vmid:";
5829 # used and unused disks
5830 my $referenced = {};
5832 # Note: it is allowed to define multiple storages with same path (alias), so
5833 # we need to check both 'volid' and real 'path' (two different volid can point
5834 # to the same path).
5836 my $referencedpath = {};
5839 foreach my $opt (keys %$conf) {
5840 if (is_valid_drivename
($opt)) {
5841 my $drive = parse_drive
($opt, $conf->{$opt});
5842 my $volid = $drive->{file
};
5845 $referenced->{$volid} = 1;
5846 if ($volid_hash->{$volid} &&
5847 (my $path = $volid_hash->{$volid}->{path
})) {
5848 $referencedpath->{$path} = 1;
5851 next if drive_is_cdrom
($drive);
5852 next if !$volid_hash->{$volid};
5854 $drive->{size
} = $volid_hash->{$volid}->{size
};
5855 my $new = print_drive
($vmid, $drive);
5856 if ($new ne $conf->{$opt}) {
5858 $conf->{$opt} = $new;
5859 print "$prefix update disk '$opt' information.\n";
5864 # remove 'unusedX' entry if volume is used
5865 foreach my $opt (keys %$conf) {
5866 next if $opt !~ m/^unused\d+$/;
5867 my $volid = $conf->{$opt};
5868 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5869 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5870 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5872 delete $conf->{$opt};
5875 $referenced->{$volid} = 1;
5876 $referencedpath->{$path} = 1 if $path;
5879 foreach my $volid (sort keys %$volid_hash) {
5880 next if $volid =~ m/vm-$vmid-state-/;
5881 next if $referenced->{$volid};
5882 my $path = $volid_hash->{$volid}->{path
};
5883 next if !$path; # just to be sure
5884 next if $referencedpath->{$path};
5886 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5887 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5888 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5895 my ($vmid, $nolock, $dryrun) = @_;
5897 my $cfg = PVE
::Storage
::config
();
5899 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5900 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5901 foreach my $stor (keys %{$cfg->{ids
}}) {
5902 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5905 print "rescan volumes...\n";
5906 my $volid_hash = scan_volids
($cfg, $vmid);
5908 my $updatefn = sub {
5911 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5913 PVE
::QemuConfig-
>check_lock($conf);
5916 foreach my $volid (keys %$volid_hash) {
5917 my $info = $volid_hash->{$volid};
5918 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5921 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5923 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5926 if (defined($vmid)) {
5930 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5933 my $vmlist = config_list
();
5934 foreach my $vmid (keys %$vmlist) {
5938 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5944 sub restore_vma_archive
{
5945 my ($archive, $vmid, $user, $opts, $comp) = @_;
5947 my $readfrom = $archive;
5949 my $cfg = PVE
::Storage
::config
();
5951 my $bwlimit = $opts->{bwlimit
};
5953 my $dbg_cmdstring = '';
5954 my $add_pipe = sub {
5956 push @$commands, $cmd;
5957 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5958 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5963 if ($archive eq '-') {
5966 # If we use a backup from a PVE defined storage we also consider that
5967 # storage's rate limit:
5968 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5969 if (defined($volid)) {
5970 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5971 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5973 print STDERR
"applying read rate limit: $readlimit\n";
5974 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5975 $add_pipe->($cstream);
5982 if ($comp eq 'gzip') {
5983 $cmd = ['zcat', $readfrom];
5984 } elsif ($comp eq 'lzop') {
5985 $cmd = ['lzop', '-d', '-c', $readfrom];
5987 die "unknown compression method '$comp'\n";
5992 my $tmpdir = "/var/tmp/vzdumptmp$$";
5995 # disable interrupts (always do cleanups)
5999 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6001 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6002 POSIX
::mkfifo
($mapfifo, 0600);
6005 my $openfifo = sub {
6006 open($fifofh, '>', $mapfifo) || die $!;
6009 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6016 my $rpcenv = PVE
::RPCEnvironment
::get
();
6018 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6019 my $tmpfn = "$conffile.$$.tmp";
6021 # Note: $oldconf is undef if VM does not exists
6022 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6023 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6027 my $print_devmap = sub {
6028 my $virtdev_hash = {};
6030 my $cfgfn = "$tmpdir/qemu-server.conf";
6032 # we can read the config - that is already extracted
6033 my $fh = IO
::File-
>new($cfgfn, "r") ||
6034 "unable to read qemu-server.conf - $!\n";
6036 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6038 my $pve_firewall_dir = '/etc/pve/firewall';
6039 mkdir $pve_firewall_dir; # make sure the dir exists
6040 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6043 while (defined(my $line = <$fh>)) {
6044 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6045 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6046 die "archive does not contain data for drive '$virtdev'\n"
6047 if !$devinfo->{$devname};
6048 if (defined($opts->{storage
})) {
6049 $storeid = $opts->{storage
} || 'local';
6050 } elsif (!$storeid) {
6053 $format = 'raw' if !$format;
6054 $devinfo->{$devname}->{devname
} = $devname;
6055 $devinfo->{$devname}->{virtdev
} = $virtdev;
6056 $devinfo->{$devname}->{format
} = $format;
6057 $devinfo->{$devname}->{storeid
} = $storeid;
6059 # check permission on storage
6060 my $pool = $opts->{pool
}; # todo: do we need that?
6061 if ($user ne 'root@pam') {
6062 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6065 $storage_limits{$storeid} = $bwlimit;
6067 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6071 foreach my $key (keys %storage_limits) {
6072 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6074 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6075 $storage_limits{$key} = $limit * 1024;
6078 foreach my $devname (keys %$devinfo) {
6079 die "found no device mapping information for device '$devname'\n"
6080 if !$devinfo->{$devname}->{virtdev
};
6083 # create empty/temp config
6085 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6086 foreach_drive
($oldconf, sub {
6087 my ($ds, $drive) = @_;
6089 return if drive_is_cdrom
($drive);
6091 my $volid = $drive->{file
};
6093 return if !$volid || $volid =~ m
|^/|;
6095 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6096 return if !$path || !$owner || ($owner != $vmid);
6098 # Note: only delete disk we want to restore
6099 # other volumes will become unused
6100 if ($virtdev_hash->{$ds}) {
6101 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6108 # delete vmstate files
6109 # since after the restore we have no snapshots anymore
6110 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6111 my $snap = $oldconf->{snapshots
}->{$snapname};
6112 if ($snap->{vmstate
}) {
6113 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6122 foreach my $virtdev (sort keys %$virtdev_hash) {
6123 my $d = $virtdev_hash->{$virtdev};
6124 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6125 my $storeid = $d->{storeid
};
6126 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6129 if (my $limit = $storage_limits{$storeid}) {
6130 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6133 # test if requested format is supported
6134 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6135 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6136 $d->{format
} = $defFormat if !$supported;
6138 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6139 $d->{format
}, undef, $alloc_size);
6140 print STDERR
"new volume ID is '$volid'\n";
6141 $d->{volid
} = $volid;
6142 my $path = PVE
::Storage
::path
($cfg, $volid);
6144 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6146 my $write_zeros = 1;
6147 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6151 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6153 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6154 $map->{$virtdev} = $volid;
6157 $fh->seek(0, 0) || die "seek failed - $!\n";
6159 my $outfd = new IO
::File
($tmpfn, "w") ||
6160 die "unable to write config for VM $vmid\n";
6162 my $cookie = { netcount
=> 0 };
6163 while (defined(my $line = <$fh>)) {
6164 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6177 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6178 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6180 $oldtimeout = alarm($timeout);
6187 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6188 my ($dev_id, $size, $devname) = ($1, $2, $3);
6189 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6190 } elsif ($line =~ m/^CTIME: /) {
6191 # we correctly received the vma config, so we can disable
6192 # the timeout now for disk allocation (set to 10 minutes, so
6193 # that we always timeout if something goes wrong)
6196 print $fifofh "done\n";
6197 my $tmp = $oldtimeout || 0;
6198 $oldtimeout = undef;
6204 print "restore vma archive: $dbg_cmdstring\n";
6205 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6209 alarm($oldtimeout) if $oldtimeout;
6212 foreach my $devname (keys %$devinfo) {
6213 my $volid = $devinfo->{$devname}->{volid
};
6214 push @$vollist, $volid if $volid;
6217 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6225 foreach my $devname (keys %$devinfo) {
6226 my $volid = $devinfo->{$devname}->{volid
};
6229 if ($volid =~ m
|^/|) {
6230 unlink $volid || die 'unlink failed\n';
6232 PVE
::Storage
::vdisk_free
($cfg, $volid);
6234 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6236 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6243 rename($tmpfn, $conffile) ||
6244 die "unable to commit configuration file '$conffile'\n";
6246 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6248 eval { rescan
($vmid, 1); };
6252 sub restore_tar_archive
{
6253 my ($archive, $vmid, $user, $opts) = @_;
6255 if ($archive ne '-') {
6256 my $firstfile = tar_archive_read_firstfile
($archive);
6257 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6258 if $firstfile ne 'qemu-server.conf';
6261 my $storecfg = PVE
::Storage
::config
();
6263 # destroy existing data - keep empty config
6264 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6265 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6267 my $tocmd = "/usr/lib/qemu-server/qmextract";
6269 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6270 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6271 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6272 $tocmd .= ' --info' if $opts->{info
};
6274 # tar option "xf" does not autodetect compression when read from STDIN,
6275 # so we pipe to zcat
6276 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6277 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6279 my $tmpdir = "/var/tmp/vzdumptmp$$";
6282 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6283 local $ENV{VZDUMP_VMID
} = $vmid;
6284 local $ENV{VZDUMP_USER
} = $user;
6286 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6287 my $tmpfn = "$conffile.$$.tmp";
6289 # disable interrupts (always do cleanups)
6293 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6301 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6303 if ($archive eq '-') {
6304 print "extracting archive from STDIN\n";
6305 run_command
($cmd, input
=> "<&STDIN");
6307 print "extracting archive '$archive'\n";
6311 return if $opts->{info
};
6315 my $statfile = "$tmpdir/qmrestore.stat";
6316 if (my $fd = IO
::File-
>new($statfile, "r")) {
6317 while (defined (my $line = <$fd>)) {
6318 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6319 $map->{$1} = $2 if $1;
6321 print STDERR
"unable to parse line in statfile - $line\n";
6327 my $confsrc = "$tmpdir/qemu-server.conf";
6329 my $srcfd = new IO
::File
($confsrc, "r") ||
6330 die "unable to open file '$confsrc'\n";
6332 my $outfd = new IO
::File
($tmpfn, "w") ||
6333 die "unable to write config for VM $vmid\n";
6335 my $cookie = { netcount
=> 0 };
6336 while (defined (my $line = <$srcfd>)) {
6337 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6349 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6356 rename $tmpfn, $conffile ||
6357 die "unable to commit configuration file '$conffile'\n";
6359 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6361 eval { rescan
($vmid, 1); };
6365 sub foreach_storage_used_by_vm
{
6366 my ($conf, $func) = @_;
6370 foreach_drive
($conf, sub {
6371 my ($ds, $drive) = @_;
6372 return if drive_is_cdrom
($drive);
6374 my $volid = $drive->{file
};
6376 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6377 $sidhash->{$sid} = $sid if $sid;
6380 foreach my $sid (sort keys %$sidhash) {
6385 sub do_snapshots_with_qemu
{
6386 my ($storecfg, $volid) = @_;
6388 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6390 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6391 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6395 if ($volid =~ m/\.(qcow2|qed)$/){
6402 sub qga_check_running
{
6403 my ($vmid, $nowarn) = @_;
6405 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6407 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6413 sub template_create
{
6414 my ($vmid, $conf, $disk) = @_;
6416 my $storecfg = PVE
::Storage
::config
();
6418 foreach_drive
($conf, sub {
6419 my ($ds, $drive) = @_;
6421 return if drive_is_cdrom
($drive);
6422 return if $disk && $ds ne $disk;
6424 my $volid = $drive->{file
};
6425 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6427 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6428 $drive->{file
} = $voliddst;
6429 $conf->{$ds} = print_drive
($vmid, $drive);
6430 PVE
::QemuConfig-
>write_config($vmid, $conf);
6434 sub qemu_img_convert
{
6435 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6437 my $storecfg = PVE
::Storage
::config
();
6438 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6439 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6441 if ($src_storeid && $dst_storeid) {
6443 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6445 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6446 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6448 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6449 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6451 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6452 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6455 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6456 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6457 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6458 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6459 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6460 if ($is_zero_initialized) {
6461 push @$cmd, "zeroinit:$dst_path";
6463 push @$cmd, $dst_path;
6468 if($line =~ m/\((\S+)\/100\
%\)/){
6470 my $transferred = int($size * $percent / 100);
6471 my $remaining = $size - $transferred;
6473 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6478 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6480 die "copy failed: $err" if $err;
6484 sub qemu_img_format
{
6485 my ($scfg, $volname) = @_;
6487 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6494 sub qemu_drive_mirror
{
6495 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6497 $jobs = {} if !$jobs;
6501 $jobs->{"drive-$drive"} = {};
6503 if ($dst_volid =~ /^nbd:/) {
6504 $qemu_target = $dst_volid;
6507 my $storecfg = PVE
::Storage
::config
();
6508 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6510 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6512 $format = qemu_img_format
($dst_scfg, $dst_volname);
6514 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6516 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6519 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6520 $opts->{format
} = $format if $format;
6522 print "drive mirror is starting for drive-$drive\n";
6524 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6527 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6528 die "mirroring error: $err";
6531 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6534 sub qemu_drive_mirror_monitor
{
6535 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6538 my $err_complete = 0;
6541 die "storage migration timed out\n" if $err_complete > 300;
6543 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6545 my $running_mirror_jobs = {};
6546 foreach my $stat (@$stats) {
6547 next if $stat->{type
} ne 'mirror';
6548 $running_mirror_jobs->{$stat->{device
}} = $stat;
6551 my $readycounter = 0;
6553 foreach my $job (keys %$jobs) {
6555 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6556 print "$job : finished\n";
6557 delete $jobs->{$job};
6561 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6563 my $busy = $running_mirror_jobs->{$job}->{busy
};
6564 my $ready = $running_mirror_jobs->{$job}->{ready
};
6565 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6566 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6567 my $remaining = $total - $transferred;
6568 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6570 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6573 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6576 last if scalar(keys %$jobs) == 0;
6578 if ($readycounter == scalar(keys %$jobs)) {
6579 print "all mirroring jobs are ready \n";
6580 last if $skipcomplete; #do the complete later
6582 if ($vmiddst && $vmiddst != $vmid) {
6583 my $agent_running = $qga && qga_check_running
($vmid);
6584 if ($agent_running) {
6585 print "freeze filesystem\n";
6586 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6588 print "suspend vm\n";
6589 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6592 # if we clone a disk for a new target vm, we don't switch the disk
6593 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6595 if ($agent_running) {
6596 print "unfreeze filesystem\n";
6597 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6599 print "resume vm\n";
6600 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6606 foreach my $job (keys %$jobs) {
6607 # try to switch the disk if source and destination are on the same guest
6608 print "$job: Completing block job...\n";
6610 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6611 if ($@ =~ m/cannot be completed/) {
6612 print "$job: Block job cannot be completed, try again.\n";
6615 print "$job: Completed successfully.\n";
6616 $jobs->{$job}->{complete
} = 1;
6627 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6628 die "mirroring error: $err";
6633 sub qemu_blockjobs_cancel
{
6634 my ($vmid, $jobs) = @_;
6636 foreach my $job (keys %$jobs) {
6637 print "$job: Cancelling block job\n";
6638 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6639 $jobs->{$job}->{cancel
} = 1;
6643 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6645 my $running_jobs = {};
6646 foreach my $stat (@$stats) {
6647 $running_jobs->{$stat->{device
}} = $stat;
6650 foreach my $job (keys %$jobs) {
6652 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6653 print "$job: Done.\n";
6654 delete $jobs->{$job};
6658 last if scalar(keys %$jobs) == 0;
6665 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6666 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6671 print "create linked clone of drive $drivename ($drive->{file})\n";
6672 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6673 push @$newvollist, $newvolid;
6676 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6677 $storeid = $storage if $storage;
6679 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6680 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6682 print "create full clone of drive $drivename ($drive->{file})\n";
6684 if (drive_is_cloudinit
($drive)) {
6685 $name = "vm-$newvmid-cloudinit";
6687 # cloudinit only supports raw and qcow2 atm:
6688 if ($dst_format eq 'qcow2') {
6690 } elsif ($dst_format ne 'raw') {
6691 die "clone: unhandled format for cloudinit image\n";
6694 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6695 push @$newvollist, $newvolid;
6697 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6699 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6700 if (!$running || $snapname) {
6701 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6704 my $kvmver = get_running_qemu_version
($vmid);
6705 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6706 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6707 if $drive->{iothread
};
6710 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6714 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6717 $disk->{format
} = undef;
6718 $disk->{file
} = $newvolid;
6719 $disk->{size
} = $size;
6724 # this only works if VM is running
6725 sub get_current_qemu_machine
{
6728 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6729 my $res = vm_qmp_command
($vmid, $cmd);
6731 my ($current, $default);
6732 foreach my $e (@$res) {
6733 $default = $e->{name
} if $e->{'is-default'};
6734 $current = $e->{name
} if $e->{'is-current'};
6737 # fallback to the default machine if current is not supported by qemu
6738 return $current || $default || 'pc';
6741 sub get_running_qemu_version
{
6743 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6744 my $res = vm_qmp_command
($vmid, $cmd);
6745 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6748 sub qemu_machine_feature_enabled
{
6749 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6754 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6756 $current_major = $3;
6757 $current_minor = $4;
6759 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6761 $current_major = $1;
6762 $current_minor = $2;
6765 return 1 if $current_major > $version_major ||
6766 ($current_major == $version_major &&
6767 $current_minor >= $version_minor);
6770 sub qemu_machine_pxe
{
6771 my ($vmid, $conf, $machine) = @_;
6773 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6775 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6782 sub qemu_use_old_bios_files
{
6783 my ($machine_type) = @_;
6785 return if !$machine_type;
6787 my $use_old_bios_files = undef;
6789 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6791 $use_old_bios_files = 1;
6793 my $kvmver = kvm_user_version
();
6794 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6795 # load new efi bios files on migration. So this hack is required to allow
6796 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6797 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6798 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6801 return ($use_old_bios_files, $machine_type);
6804 sub create_efidisk
($$$$$) {
6805 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6807 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6808 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6810 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6811 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6812 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6814 my $path = PVE
::Storage
::path
($storecfg, $volid);
6816 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6818 die "Copying EFI vars image failed: $@" if $@;
6820 return ($volid, $vars_size);
6823 sub vm_iothreads_list
{
6826 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6829 foreach my $iothread (@$res) {
6830 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6837 my ($conf, $drive) = @_;
6841 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6843 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6849 my $controller = int($drive->{index} / $maxdev);
6850 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6852 return ($maxdev, $controller, $controller_prefix);
6855 sub add_hyperv_enlightenments
{
6856 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
6858 return if $winversion < 6;
6859 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6861 if ($gpu_passthrough || defined($hv_vendor_id)) {
6862 $hv_vendor_id //= 'proxmox';
6863 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
6866 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6867 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6868 push @$cpuFlags , 'hv_vapic';
6869 push @$cpuFlags , 'hv_time';
6871 push @$cpuFlags , 'hv_spinlocks=0xffff';
6874 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6875 push @$cpuFlags , 'hv_reset';
6876 push @$cpuFlags , 'hv_vpindex';
6877 push @$cpuFlags , 'hv_runtime';
6880 if ($winversion >= 7) {
6881 push @$cpuFlags , 'hv_relaxed';
6883 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6884 push @$cpuFlags , 'hv_synic';
6885 push @$cpuFlags , 'hv_stimer';
6890 sub windows_version
{
6893 return 0 if !$ostype;
6897 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6899 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6901 } elsif ($ostype =~ m/^win(\d+)$/) {
6908 sub resolve_dst_disk_format
{
6909 my ($storecfg, $storeid, $src_volname, $format) = @_;
6910 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6913 # if no target format is specified, use the source disk format as hint
6915 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6916 $format = qemu_img_format
($scfg, $src_volname);
6922 # test if requested format is supported - else use default
6923 my $supported = grep { $_ eq $format } @$validFormats;
6924 $format = $defFormat if !$supported;
6928 sub resolve_first_disk
{
6930 my @disks = PVE
::QemuServer
::valid_drive_names
();
6932 foreach my $ds (reverse @disks) {
6933 next if !$conf->{$ds};
6934 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6935 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6942 my ($uuid, $uuid_str);
6943 UUID
::generate
($uuid);
6944 UUID
::unparse
($uuid, $uuid_str);
6948 sub generate_smbios1_uuid
{
6949 return "uuid=".generate_uuid
();
6955 vm_mon_cmd
($vmid, 'nbd-server-stop');
6958 # bash completion helper
6960 sub complete_backup_archives
{
6961 my ($cmdname, $pname, $cvalue) = @_;
6963 my $cfg = PVE
::Storage
::config
();
6967 if ($cvalue =~ m/^([^:]+):/) {
6971 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6974 foreach my $id (keys %$data) {
6975 foreach my $item (@{$data->{$id}}) {
6976 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6977 push @$res, $item->{volid
} if defined($item->{volid
});
6984 my $complete_vmid_full = sub {
6987 my $idlist = vmstatus
();
6991 foreach my $id (keys %$idlist) {
6992 my $d = $idlist->{$id};
6993 if (defined($running)) {
6994 next if $d->{template
};
6995 next if $running && $d->{status
} ne 'running';
6996 next if !$running && $d->{status
} eq 'running';
7005 return &$complete_vmid_full();
7008 sub complete_vmid_stopped
{
7009 return &$complete_vmid_full(0);
7012 sub complete_vmid_running
{
7013 return &$complete_vmid_full(1);
7016 sub complete_storage
{
7018 my $cfg = PVE
::Storage
::config
();
7019 my $ids = $cfg->{ids
};
7022 foreach my $sid (keys %$ids) {
7023 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7024 next if !$ids->{$sid}->{content
}->{images
};