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" if !defined($snapshot);
5383 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
5388 my $defaults = load_defaults();
5390 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5392 return PVE::Tools::cmd2string($cmd);
5396 my ($vmid, $skiplock) = @_;
5398 PVE::QemuConfig->lock_config($vmid, sub {
5400 my $conf = PVE::QemuConfig->load_config($vmid);
5402 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5404 vm_mon_cmd($vmid, "system_reset");
5408 sub get_vm_volumes {
5412 foreach_volid($conf, sub {
5413 my ($volid, $attr) = @_;
5415 return if $volid =~ m|^/|;
5417 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5420 push @$vollist, $volid;
5426 sub vm_stop_cleanup {
5427 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5432 my $vollist = get_vm_volumes($conf);
5433 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5436 foreach my $ext (qw(mon qmp pid vnc qga)) {
5437 unlink "/var/run/qemu-server/${vmid}.$ext";
5440 foreach my $key (keys %$conf) {
5441 next if $key !~ m/^hostpci(\d+)$/;
5442 my $hostpciindex = $1;
5443 my $d = parse_hostpci
($conf->{$key});
5444 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5446 foreach my $pci (@{$d->{pciid
}}) {
5447 my $pciid = $pci->{id
};
5448 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5452 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5454 warn $@ if $@; # avoid errors - just warn
5457 # Note: use $nockeck to skip tests if VM configuration file exists.
5458 # We need that when migration VMs to other nodes (files already moved)
5459 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5461 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5463 $force = 1 if !defined($force) && !$shutdown;
5466 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5467 kill 15, $pid if $pid;
5468 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5469 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5473 PVE
::QemuConfig-
>lock_config($vmid, sub {
5475 my $pid = check_running
($vmid, $nocheck);
5480 $conf = PVE
::QemuConfig-
>load_config($vmid);
5481 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5482 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5483 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5484 $timeout = $opts->{down
} if $opts->{down
};
5488 $timeout = 60 if !defined($timeout);
5492 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5493 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5495 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5498 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5505 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5510 if ($count >= $timeout) {
5512 warn "VM still running - terminating now with SIGTERM\n";
5515 die "VM quit/powerdown failed - got timeout\n";
5518 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5523 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5526 die "VM quit/powerdown failed\n";
5534 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5539 if ($count >= $timeout) {
5540 warn "VM still running - terminating now with SIGKILL\n";
5545 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5550 my ($vmid, $skiplock) = @_;
5552 PVE
::QemuConfig-
>lock_config($vmid, sub {
5554 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5556 PVE
::QemuConfig-
>check_lock($conf)
5557 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5559 vm_mon_cmd
($vmid, "stop");
5564 my ($vmid, $skiplock, $nocheck) = @_;
5566 PVE
::QemuConfig-
>lock_config($vmid, sub {
5568 my $res = vm_mon_cmd
($vmid, 'query-status');
5569 my $resume_cmd = 'cont';
5571 if ($res->{status
} && $res->{status
} eq 'suspended') {
5572 $resume_cmd = 'system_wakeup';
5577 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5579 PVE
::QemuConfig-
>check_lock($conf)
5580 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5582 vm_mon_cmd
($vmid, $resume_cmd);
5585 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5591 my ($vmid, $skiplock, $key) = @_;
5593 PVE
::QemuConfig-
>lock_config($vmid, sub {
5595 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5597 # there is no qmp command, so we use the human monitor command
5598 vm_human_monitor_command
($vmid, "sendkey $key");
5603 my ($storecfg, $vmid, $skiplock) = @_;
5605 PVE
::QemuConfig-
>lock_config($vmid, sub {
5607 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5609 if (!check_running
($vmid)) {
5610 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5612 die "VM $vmid is running - destroy failed\n";
5617 # vzdump restore implementaion
5619 sub tar_archive_read_firstfile
{
5620 my $archive = shift;
5622 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5624 # try to detect archive type first
5625 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5626 die "unable to open file '$archive'\n";
5627 my $firstfile = <$fh>;
5631 die "ERROR: archive contaions no data\n" if !$firstfile;
5637 sub tar_restore_cleanup
{
5638 my ($storecfg, $statfile) = @_;
5640 print STDERR
"starting cleanup\n";
5642 if (my $fd = IO
::File-
>new($statfile, "r")) {
5643 while (defined(my $line = <$fd>)) {
5644 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5647 if ($volid =~ m
|^/|) {
5648 unlink $volid || die 'unlink failed\n';
5650 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5652 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5654 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5656 print STDERR
"unable to parse line in statfile - $line";
5663 sub restore_archive
{
5664 my ($archive, $vmid, $user, $opts) = @_;
5666 my $format = $opts->{format
};
5669 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5670 $format = 'tar' if !$format;
5672 } elsif ($archive =~ m/\.tar$/) {
5673 $format = 'tar' if !$format;
5674 } elsif ($archive =~ m/.tar.lzo$/) {
5675 $format = 'tar' if !$format;
5677 } elsif ($archive =~ m/\.vma$/) {
5678 $format = 'vma' if !$format;
5679 } elsif ($archive =~ m/\.vma\.gz$/) {
5680 $format = 'vma' if !$format;
5682 } elsif ($archive =~ m/\.vma\.lzo$/) {
5683 $format = 'vma' if !$format;
5686 $format = 'vma' if !$format; # default
5689 # try to detect archive format
5690 if ($format eq 'tar') {
5691 return restore_tar_archive
($archive, $vmid, $user, $opts);
5693 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5697 sub restore_update_config_line
{
5698 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5700 return if $line =~ m/^\#qmdump\#/;
5701 return if $line =~ m/^\#vzdump\#/;
5702 return if $line =~ m/^lock:/;
5703 return if $line =~ m/^unused\d+:/;
5704 return if $line =~ m/^parent:/;
5705 return if $line =~ m/^template:/; # restored VM is never a template
5707 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5708 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5709 # try to convert old 1.X settings
5710 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5711 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5712 my ($model, $macaddr) = split(/\=/, $devconfig);
5713 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5716 bridge
=> "vmbr$ind",
5717 macaddr
=> $macaddr,
5719 my $netstr = print_net
($net);
5721 print $outfd "net$cookie->{netcount}: $netstr\n";
5722 $cookie->{netcount
}++;
5724 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5725 my ($id, $netstr) = ($1, $2);
5726 my $net = parse_net
($netstr);
5727 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5728 $netstr = print_net
($net);
5729 print $outfd "$id: $netstr\n";
5730 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5733 my $di = parse_drive
($virtdev, $value);
5734 if (defined($di->{backup
}) && !$di->{backup
}) {
5735 print $outfd "#$line";
5736 } elsif ($map->{$virtdev}) {
5737 delete $di->{format
}; # format can change on restore
5738 $di->{file
} = $map->{$virtdev};
5739 $value = print_drive
($vmid, $di);
5740 print $outfd "$virtdev: $value\n";
5744 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5746 if ($vmgenid ne '0') {
5747 # always generate a new vmgenid if there was a valid one setup
5748 $vmgenid = generate_uuid
();
5750 print $outfd "vmgenid: $vmgenid\n";
5751 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5752 my ($uuid, $uuid_str);
5753 UUID
::generate
($uuid);
5754 UUID
::unparse
($uuid, $uuid_str);
5755 my $smbios1 = parse_smbios1
($2);
5756 $smbios1->{uuid
} = $uuid_str;
5757 print $outfd $1.print_smbios1
($smbios1)."\n";
5764 my ($cfg, $vmid) = @_;
5766 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5768 my $volid_hash = {};
5769 foreach my $storeid (keys %$info) {
5770 foreach my $item (@{$info->{$storeid}}) {
5771 next if !($item->{volid
} && $item->{size
});
5772 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5773 $volid_hash->{$item->{volid
}} = $item;
5780 sub is_volume_in_use
{
5781 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5783 my $path = PVE
::Storage
::path
($storecfg, $volid);
5785 my $scan_config = sub {
5786 my ($cref, $snapname) = @_;
5788 foreach my $key (keys %$cref) {
5789 my $value = $cref->{$key};
5790 if (is_valid_drivename
($key)) {
5791 next if $skip_drive && $key eq $skip_drive;
5792 my $drive = parse_drive
($key, $value);
5793 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5794 return 1 if $volid eq $drive->{file
};
5795 if ($drive->{file
} =~ m!^/!) {
5796 return 1 if $drive->{file
} eq $path;
5798 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5800 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5802 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5810 return 1 if &$scan_config($conf);
5814 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5815 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5821 sub update_disksize
{
5822 my ($vmid, $conf, $volid_hash) = @_;
5825 my $prefix = "VM $vmid:";
5827 # used and unused disks
5828 my $referenced = {};
5830 # Note: it is allowed to define multiple storages with same path (alias), so
5831 # we need to check both 'volid' and real 'path' (two different volid can point
5832 # to the same path).
5834 my $referencedpath = {};
5837 foreach my $opt (keys %$conf) {
5838 if (is_valid_drivename
($opt)) {
5839 my $drive = parse_drive
($opt, $conf->{$opt});
5840 my $volid = $drive->{file
};
5843 $referenced->{$volid} = 1;
5844 if ($volid_hash->{$volid} &&
5845 (my $path = $volid_hash->{$volid}->{path
})) {
5846 $referencedpath->{$path} = 1;
5849 next if drive_is_cdrom
($drive);
5850 next if !$volid_hash->{$volid};
5852 $drive->{size
} = $volid_hash->{$volid}->{size
};
5853 my $new = print_drive
($vmid, $drive);
5854 if ($new ne $conf->{$opt}) {
5856 $conf->{$opt} = $new;
5857 print "$prefix update disk '$opt' information.\n";
5862 # remove 'unusedX' entry if volume is used
5863 foreach my $opt (keys %$conf) {
5864 next if $opt !~ m/^unused\d+$/;
5865 my $volid = $conf->{$opt};
5866 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5867 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5868 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5870 delete $conf->{$opt};
5873 $referenced->{$volid} = 1;
5874 $referencedpath->{$path} = 1 if $path;
5877 foreach my $volid (sort keys %$volid_hash) {
5878 next if $volid =~ m/vm-$vmid-state-/;
5879 next if $referenced->{$volid};
5880 my $path = $volid_hash->{$volid}->{path
};
5881 next if !$path; # just to be sure
5882 next if $referencedpath->{$path};
5884 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5885 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5886 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5893 my ($vmid, $nolock, $dryrun) = @_;
5895 my $cfg = PVE
::Storage
::config
();
5897 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5898 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5899 foreach my $stor (keys %{$cfg->{ids
}}) {
5900 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5903 print "rescan volumes...\n";
5904 my $volid_hash = scan_volids
($cfg, $vmid);
5906 my $updatefn = sub {
5909 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5911 PVE
::QemuConfig-
>check_lock($conf);
5914 foreach my $volid (keys %$volid_hash) {
5915 my $info = $volid_hash->{$volid};
5916 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5919 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5921 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5924 if (defined($vmid)) {
5928 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5931 my $vmlist = config_list
();
5932 foreach my $vmid (keys %$vmlist) {
5936 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5942 sub restore_vma_archive
{
5943 my ($archive, $vmid, $user, $opts, $comp) = @_;
5945 my $readfrom = $archive;
5947 my $cfg = PVE
::Storage
::config
();
5949 my $bwlimit = $opts->{bwlimit
};
5951 my $dbg_cmdstring = '';
5952 my $add_pipe = sub {
5954 push @$commands, $cmd;
5955 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5956 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5961 if ($archive eq '-') {
5964 # If we use a backup from a PVE defined storage we also consider that
5965 # storage's rate limit:
5966 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5967 if (defined($volid)) {
5968 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5969 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5971 print STDERR
"applying read rate limit: $readlimit\n";
5972 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5973 $add_pipe->($cstream);
5980 if ($comp eq 'gzip') {
5981 $cmd = ['zcat', $readfrom];
5982 } elsif ($comp eq 'lzop') {
5983 $cmd = ['lzop', '-d', '-c', $readfrom];
5985 die "unknown compression method '$comp'\n";
5990 my $tmpdir = "/var/tmp/vzdumptmp$$";
5993 # disable interrupts (always do cleanups)
5997 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5999 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6000 POSIX
::mkfifo
($mapfifo, 0600);
6003 my $openfifo = sub {
6004 open($fifofh, '>', $mapfifo) || die $!;
6007 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6014 my $rpcenv = PVE
::RPCEnvironment
::get
();
6016 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6017 my $tmpfn = "$conffile.$$.tmp";
6019 # Note: $oldconf is undef if VM does not exists
6020 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6021 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6025 my $print_devmap = sub {
6026 my $virtdev_hash = {};
6028 my $cfgfn = "$tmpdir/qemu-server.conf";
6030 # we can read the config - that is already extracted
6031 my $fh = IO
::File-
>new($cfgfn, "r") ||
6032 "unable to read qemu-server.conf - $!\n";
6034 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6036 my $pve_firewall_dir = '/etc/pve/firewall';
6037 mkdir $pve_firewall_dir; # make sure the dir exists
6038 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6041 while (defined(my $line = <$fh>)) {
6042 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6043 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6044 die "archive does not contain data for drive '$virtdev'\n"
6045 if !$devinfo->{$devname};
6046 if (defined($opts->{storage
})) {
6047 $storeid = $opts->{storage
} || 'local';
6048 } elsif (!$storeid) {
6051 $format = 'raw' if !$format;
6052 $devinfo->{$devname}->{devname
} = $devname;
6053 $devinfo->{$devname}->{virtdev
} = $virtdev;
6054 $devinfo->{$devname}->{format
} = $format;
6055 $devinfo->{$devname}->{storeid
} = $storeid;
6057 # check permission on storage
6058 my $pool = $opts->{pool
}; # todo: do we need that?
6059 if ($user ne 'root@pam') {
6060 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6063 $storage_limits{$storeid} = $bwlimit;
6065 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6069 foreach my $key (keys %storage_limits) {
6070 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6072 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6073 $storage_limits{$key} = $limit * 1024;
6076 foreach my $devname (keys %$devinfo) {
6077 die "found no device mapping information for device '$devname'\n"
6078 if !$devinfo->{$devname}->{virtdev
};
6081 # create empty/temp config
6083 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6084 foreach_drive
($oldconf, sub {
6085 my ($ds, $drive) = @_;
6087 return if drive_is_cdrom
($drive);
6089 my $volid = $drive->{file
};
6091 return if !$volid || $volid =~ m
|^/|;
6093 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6094 return if !$path || !$owner || ($owner != $vmid);
6096 # Note: only delete disk we want to restore
6097 # other volumes will become unused
6098 if ($virtdev_hash->{$ds}) {
6099 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6106 # delete vmstate files
6107 # since after the restore we have no snapshots anymore
6108 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6109 my $snap = $oldconf->{snapshots
}->{$snapname};
6110 if ($snap->{vmstate
}) {
6111 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6120 foreach my $virtdev (sort keys %$virtdev_hash) {
6121 my $d = $virtdev_hash->{$virtdev};
6122 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6123 my $storeid = $d->{storeid
};
6124 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6127 if (my $limit = $storage_limits{$storeid}) {
6128 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6131 # test if requested format is supported
6132 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6133 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6134 $d->{format
} = $defFormat if !$supported;
6136 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6137 $d->{format
}, undef, $alloc_size);
6138 print STDERR
"new volume ID is '$volid'\n";
6139 $d->{volid
} = $volid;
6140 my $path = PVE
::Storage
::path
($cfg, $volid);
6142 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6144 my $write_zeros = 1;
6145 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6149 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6151 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6152 $map->{$virtdev} = $volid;
6155 $fh->seek(0, 0) || die "seek failed - $!\n";
6157 my $outfd = new IO
::File
($tmpfn, "w") ||
6158 die "unable to write config for VM $vmid\n";
6160 my $cookie = { netcount
=> 0 };
6161 while (defined(my $line = <$fh>)) {
6162 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6175 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6176 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6178 $oldtimeout = alarm($timeout);
6185 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6186 my ($dev_id, $size, $devname) = ($1, $2, $3);
6187 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6188 } elsif ($line =~ m/^CTIME: /) {
6189 # we correctly received the vma config, so we can disable
6190 # the timeout now for disk allocation (set to 10 minutes, so
6191 # that we always timeout if something goes wrong)
6194 print $fifofh "done\n";
6195 my $tmp = $oldtimeout || 0;
6196 $oldtimeout = undef;
6202 print "restore vma archive: $dbg_cmdstring\n";
6203 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6207 alarm($oldtimeout) if $oldtimeout;
6210 foreach my $devname (keys %$devinfo) {
6211 my $volid = $devinfo->{$devname}->{volid
};
6212 push @$vollist, $volid if $volid;
6215 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6223 foreach my $devname (keys %$devinfo) {
6224 my $volid = $devinfo->{$devname}->{volid
};
6227 if ($volid =~ m
|^/|) {
6228 unlink $volid || die 'unlink failed\n';
6230 PVE
::Storage
::vdisk_free
($cfg, $volid);
6232 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6234 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6241 rename($tmpfn, $conffile) ||
6242 die "unable to commit configuration file '$conffile'\n";
6244 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6246 eval { rescan
($vmid, 1); };
6250 sub restore_tar_archive
{
6251 my ($archive, $vmid, $user, $opts) = @_;
6253 if ($archive ne '-') {
6254 my $firstfile = tar_archive_read_firstfile
($archive);
6255 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6256 if $firstfile ne 'qemu-server.conf';
6259 my $storecfg = PVE
::Storage
::config
();
6261 # destroy existing data - keep empty config
6262 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6263 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6265 my $tocmd = "/usr/lib/qemu-server/qmextract";
6267 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6268 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6269 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6270 $tocmd .= ' --info' if $opts->{info
};
6272 # tar option "xf" does not autodetect compression when read from STDIN,
6273 # so we pipe to zcat
6274 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6275 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6277 my $tmpdir = "/var/tmp/vzdumptmp$$";
6280 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6281 local $ENV{VZDUMP_VMID
} = $vmid;
6282 local $ENV{VZDUMP_USER
} = $user;
6284 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6285 my $tmpfn = "$conffile.$$.tmp";
6287 # disable interrupts (always do cleanups)
6291 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6299 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6301 if ($archive eq '-') {
6302 print "extracting archive from STDIN\n";
6303 run_command
($cmd, input
=> "<&STDIN");
6305 print "extracting archive '$archive'\n";
6309 return if $opts->{info
};
6313 my $statfile = "$tmpdir/qmrestore.stat";
6314 if (my $fd = IO
::File-
>new($statfile, "r")) {
6315 while (defined (my $line = <$fd>)) {
6316 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6317 $map->{$1} = $2 if $1;
6319 print STDERR
"unable to parse line in statfile - $line\n";
6325 my $confsrc = "$tmpdir/qemu-server.conf";
6327 my $srcfd = new IO
::File
($confsrc, "r") ||
6328 die "unable to open file '$confsrc'\n";
6330 my $outfd = new IO
::File
($tmpfn, "w") ||
6331 die "unable to write config for VM $vmid\n";
6333 my $cookie = { netcount
=> 0 };
6334 while (defined (my $line = <$srcfd>)) {
6335 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6347 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6354 rename $tmpfn, $conffile ||
6355 die "unable to commit configuration file '$conffile'\n";
6357 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6359 eval { rescan
($vmid, 1); };
6363 sub foreach_storage_used_by_vm
{
6364 my ($conf, $func) = @_;
6368 foreach_drive
($conf, sub {
6369 my ($ds, $drive) = @_;
6370 return if drive_is_cdrom
($drive);
6372 my $volid = $drive->{file
};
6374 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6375 $sidhash->{$sid} = $sid if $sid;
6378 foreach my $sid (sort keys %$sidhash) {
6383 sub do_snapshots_with_qemu
{
6384 my ($storecfg, $volid) = @_;
6386 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6388 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6389 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6393 if ($volid =~ m/\.(qcow2|qed)$/){
6400 sub qga_check_running
{
6401 my ($vmid, $nowarn) = @_;
6403 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6405 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6411 sub template_create
{
6412 my ($vmid, $conf, $disk) = @_;
6414 my $storecfg = PVE
::Storage
::config
();
6416 foreach_drive
($conf, sub {
6417 my ($ds, $drive) = @_;
6419 return if drive_is_cdrom
($drive);
6420 return if $disk && $ds ne $disk;
6422 my $volid = $drive->{file
};
6423 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6425 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6426 $drive->{file
} = $voliddst;
6427 $conf->{$ds} = print_drive
($vmid, $drive);
6428 PVE
::QemuConfig-
>write_config($vmid, $conf);
6432 sub qemu_img_convert
{
6433 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6435 my $storecfg = PVE
::Storage
::config
();
6436 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6437 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6439 if ($src_storeid && $dst_storeid) {
6441 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6443 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6444 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6446 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6447 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6449 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6450 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6453 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6454 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6455 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6456 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6457 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6458 if ($is_zero_initialized) {
6459 push @$cmd, "zeroinit:$dst_path";
6461 push @$cmd, $dst_path;
6466 if($line =~ m/\((\S+)\/100\
%\)/){
6468 my $transferred = int($size * $percent / 100);
6469 my $remaining = $size - $transferred;
6471 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6476 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6478 die "copy failed: $err" if $err;
6482 sub qemu_img_format
{
6483 my ($scfg, $volname) = @_;
6485 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6492 sub qemu_drive_mirror
{
6493 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6495 $jobs = {} if !$jobs;
6499 $jobs->{"drive-$drive"} = {};
6501 if ($dst_volid =~ /^nbd:/) {
6502 $qemu_target = $dst_volid;
6505 my $storecfg = PVE
::Storage
::config
();
6506 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6508 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6510 $format = qemu_img_format
($dst_scfg, $dst_volname);
6512 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6514 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6517 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6518 $opts->{format
} = $format if $format;
6520 print "drive mirror is starting for drive-$drive\n";
6522 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6525 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6526 die "mirroring error: $err";
6529 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6532 sub qemu_drive_mirror_monitor
{
6533 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6536 my $err_complete = 0;
6539 die "storage migration timed out\n" if $err_complete > 300;
6541 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6543 my $running_mirror_jobs = {};
6544 foreach my $stat (@$stats) {
6545 next if $stat->{type
} ne 'mirror';
6546 $running_mirror_jobs->{$stat->{device
}} = $stat;
6549 my $readycounter = 0;
6551 foreach my $job (keys %$jobs) {
6553 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6554 print "$job : finished\n";
6555 delete $jobs->{$job};
6559 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6561 my $busy = $running_mirror_jobs->{$job}->{busy
};
6562 my $ready = $running_mirror_jobs->{$job}->{ready
};
6563 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6564 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6565 my $remaining = $total - $transferred;
6566 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6568 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6571 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6574 last if scalar(keys %$jobs) == 0;
6576 if ($readycounter == scalar(keys %$jobs)) {
6577 print "all mirroring jobs are ready \n";
6578 last if $skipcomplete; #do the complete later
6580 if ($vmiddst && $vmiddst != $vmid) {
6581 my $agent_running = $qga && qga_check_running
($vmid);
6582 if ($agent_running) {
6583 print "freeze filesystem\n";
6584 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6586 print "suspend vm\n";
6587 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6590 # if we clone a disk for a new target vm, we don't switch the disk
6591 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6593 if ($agent_running) {
6594 print "unfreeze filesystem\n";
6595 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6597 print "resume vm\n";
6598 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6604 foreach my $job (keys %$jobs) {
6605 # try to switch the disk if source and destination are on the same guest
6606 print "$job: Completing block job...\n";
6608 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6609 if ($@ =~ m/cannot be completed/) {
6610 print "$job: Block job cannot be completed, try again.\n";
6613 print "$job: Completed successfully.\n";
6614 $jobs->{$job}->{complete
} = 1;
6625 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6626 die "mirroring error: $err";
6631 sub qemu_blockjobs_cancel
{
6632 my ($vmid, $jobs) = @_;
6634 foreach my $job (keys %$jobs) {
6635 print "$job: Cancelling block job\n";
6636 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6637 $jobs->{$job}->{cancel
} = 1;
6641 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6643 my $running_jobs = {};
6644 foreach my $stat (@$stats) {
6645 $running_jobs->{$stat->{device
}} = $stat;
6648 foreach my $job (keys %$jobs) {
6650 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6651 print "$job: Done.\n";
6652 delete $jobs->{$job};
6656 last if scalar(keys %$jobs) == 0;
6663 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6664 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6669 print "create linked clone of drive $drivename ($drive->{file})\n";
6670 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6671 push @$newvollist, $newvolid;
6674 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6675 $storeid = $storage if $storage;
6677 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6678 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6680 print "create full clone of drive $drivename ($drive->{file})\n";
6682 if (drive_is_cloudinit
($drive)) {
6683 $name = "vm-$newvmid-cloudinit";
6685 # cloudinit only supports raw and qcow2 atm:
6686 if ($dst_format eq 'qcow2') {
6688 } elsif ($dst_format ne 'raw') {
6689 die "clone: unhandled format for cloudinit image\n";
6692 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6693 push @$newvollist, $newvolid;
6695 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6697 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6698 if (!$running || $snapname) {
6699 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6702 my $kvmver = get_running_qemu_version
($vmid);
6703 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6704 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6705 if $drive->{iothread
};
6708 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6712 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6715 $disk->{format
} = undef;
6716 $disk->{file
} = $newvolid;
6717 $disk->{size
} = $size;
6722 # this only works if VM is running
6723 sub get_current_qemu_machine
{
6726 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6727 my $res = vm_qmp_command
($vmid, $cmd);
6729 my ($current, $default);
6730 foreach my $e (@$res) {
6731 $default = $e->{name
} if $e->{'is-default'};
6732 $current = $e->{name
} if $e->{'is-current'};
6735 # fallback to the default machine if current is not supported by qemu
6736 return $current || $default || 'pc';
6739 sub get_running_qemu_version
{
6741 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6742 my $res = vm_qmp_command
($vmid, $cmd);
6743 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6746 sub qemu_machine_feature_enabled
{
6747 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6752 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6754 $current_major = $3;
6755 $current_minor = $4;
6757 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6759 $current_major = $1;
6760 $current_minor = $2;
6763 return 1 if $current_major > $version_major ||
6764 ($current_major == $version_major &&
6765 $current_minor >= $version_minor);
6768 sub qemu_machine_pxe
{
6769 my ($vmid, $conf, $machine) = @_;
6771 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6773 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6780 sub qemu_use_old_bios_files
{
6781 my ($machine_type) = @_;
6783 return if !$machine_type;
6785 my $use_old_bios_files = undef;
6787 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6789 $use_old_bios_files = 1;
6791 my $kvmver = kvm_user_version
();
6792 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6793 # load new efi bios files on migration. So this hack is required to allow
6794 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6795 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6796 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6799 return ($use_old_bios_files, $machine_type);
6802 sub create_efidisk
($$$$$) {
6803 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6805 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6806 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6808 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6809 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6810 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6812 my $path = PVE
::Storage
::path
($storecfg, $volid);
6814 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6816 die "Copying EFI vars image failed: $@" if $@;
6818 return ($volid, $vars_size);
6821 sub vm_iothreads_list
{
6824 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6827 foreach my $iothread (@$res) {
6828 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6835 my ($conf, $drive) = @_;
6839 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6841 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6847 my $controller = int($drive->{index} / $maxdev);
6848 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6850 return ($maxdev, $controller, $controller_prefix);
6853 sub add_hyperv_enlightenments
{
6854 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
6856 return if $winversion < 6;
6857 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6859 if ($gpu_passthrough || defined($hv_vendor_id)) {
6860 $hv_vendor_id //= 'proxmox';
6861 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
6864 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6865 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6866 push @$cpuFlags , 'hv_vapic';
6867 push @$cpuFlags , 'hv_time';
6869 push @$cpuFlags , 'hv_spinlocks=0xffff';
6872 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6873 push @$cpuFlags , 'hv_reset';
6874 push @$cpuFlags , 'hv_vpindex';
6875 push @$cpuFlags , 'hv_runtime';
6878 if ($winversion >= 7) {
6879 push @$cpuFlags , 'hv_relaxed';
6881 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6882 push @$cpuFlags , 'hv_synic';
6883 push @$cpuFlags , 'hv_stimer';
6888 sub windows_version
{
6891 return 0 if !$ostype;
6895 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6897 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6899 } elsif ($ostype =~ m/^win(\d+)$/) {
6906 sub resolve_dst_disk_format
{
6907 my ($storecfg, $storeid, $src_volname, $format) = @_;
6908 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6911 # if no target format is specified, use the source disk format as hint
6913 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6914 $format = qemu_img_format
($scfg, $src_volname);
6920 # test if requested format is supported - else use default
6921 my $supported = grep { $_ eq $format } @$validFormats;
6922 $format = $defFormat if !$supported;
6926 sub resolve_first_disk
{
6928 my @disks = PVE
::QemuServer
::valid_drive_names
();
6930 foreach my $ds (reverse @disks) {
6931 next if !$conf->{$ds};
6932 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6933 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6940 my ($uuid, $uuid_str);
6941 UUID
::generate
($uuid);
6942 UUID
::unparse
($uuid, $uuid_str);
6946 sub generate_smbios1_uuid
{
6947 return "uuid=".generate_uuid
();
6953 vm_mon_cmd
($vmid, 'nbd-server-stop');
6956 # bash completion helper
6958 sub complete_backup_archives
{
6959 my ($cmdname, $pname, $cvalue) = @_;
6961 my $cfg = PVE
::Storage
::config
();
6965 if ($cvalue =~ m/^([^:]+):/) {
6969 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6972 foreach my $id (keys %$data) {
6973 foreach my $item (@{$data->{$id}}) {
6974 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6975 push @$res, $item->{volid
} if defined($item->{volid
});
6982 my $complete_vmid_full = sub {
6985 my $idlist = vmstatus
();
6989 foreach my $id (keys %$idlist) {
6990 my $d = $idlist->{$id};
6991 if (defined($running)) {
6992 next if $d->{template
};
6993 next if $running && $d->{status
} ne 'running';
6994 next if !$running && $d->{status
} eq 'running';
7003 return &$complete_vmid_full();
7006 sub complete_vmid_stopped
{
7007 return &$complete_vmid_full(0);
7010 sub complete_vmid_running
{
7011 return &$complete_vmid_full(1);
7014 sub complete_storage
{
7016 my $cfg = PVE
::Storage
::config
();
7017 my $ids = $cfg->{ids
};
7020 foreach my $sid (keys %$ids) {
7021 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7022 next if !$ids->{$sid}->{content
}->{images
};