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) = @_;
5377 my $conf = PVE::QemuConfig->load_config($vmid);
5379 my $defaults = load_defaults();
5381 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5383 return PVE::Tools::cmd2string($cmd);
5387 my ($vmid, $skiplock) = @_;
5389 PVE::QemuConfig->lock_config($vmid, sub {
5391 my $conf = PVE::QemuConfig->load_config($vmid);
5393 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5395 vm_mon_cmd($vmid, "system_reset");
5399 sub get_vm_volumes {
5403 foreach_volid($conf, sub {
5404 my ($volid, $attr) = @_;
5406 return if $volid =~ m|^/|;
5408 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5411 push @$vollist, $volid;
5417 sub vm_stop_cleanup {
5418 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5423 my $vollist = get_vm_volumes($conf);
5424 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5427 foreach my $ext (qw(mon qmp pid vnc qga)) {
5428 unlink "/var/run/qemu-server/${vmid}.$ext";
5431 foreach my $key (keys %$conf) {
5432 next if $key !~ m/^hostpci(\d+)$/;
5433 my $hostpciindex = $1;
5434 my $d = parse_hostpci
($conf->{$key});
5435 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5437 foreach my $pci (@{$d->{pciid
}}) {
5438 my $pciid = $pci->{id
};
5439 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5443 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5445 warn $@ if $@; # avoid errors - just warn
5448 # Note: use $nockeck to skip tests if VM configuration file exists.
5449 # We need that when migration VMs to other nodes (files already moved)
5450 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5452 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5454 $force = 1 if !defined($force) && !$shutdown;
5457 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5458 kill 15, $pid if $pid;
5459 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5460 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5464 PVE
::QemuConfig-
>lock_config($vmid, sub {
5466 my $pid = check_running
($vmid, $nocheck);
5471 $conf = PVE
::QemuConfig-
>load_config($vmid);
5472 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5473 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5474 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5475 $timeout = $opts->{down
} if $opts->{down
};
5479 $timeout = 60 if !defined($timeout);
5483 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5484 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5486 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5489 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5496 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5501 if ($count >= $timeout) {
5503 warn "VM still running - terminating now with SIGTERM\n";
5506 die "VM quit/powerdown failed - got timeout\n";
5509 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5514 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5517 die "VM quit/powerdown failed\n";
5525 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5530 if ($count >= $timeout) {
5531 warn "VM still running - terminating now with SIGKILL\n";
5536 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5541 my ($vmid, $skiplock) = @_;
5543 PVE
::QemuConfig-
>lock_config($vmid, sub {
5545 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5547 PVE
::QemuConfig-
>check_lock($conf)
5548 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5550 vm_mon_cmd
($vmid, "stop");
5555 my ($vmid, $skiplock, $nocheck) = @_;
5557 PVE
::QemuConfig-
>lock_config($vmid, sub {
5559 my $res = vm_mon_cmd
($vmid, 'query-status');
5560 my $resume_cmd = 'cont';
5562 if ($res->{status
} && $res->{status
} eq 'suspended') {
5563 $resume_cmd = 'system_wakeup';
5568 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5570 PVE
::QemuConfig-
>check_lock($conf)
5571 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5573 vm_mon_cmd
($vmid, $resume_cmd);
5576 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5582 my ($vmid, $skiplock, $key) = @_;
5584 PVE
::QemuConfig-
>lock_config($vmid, sub {
5586 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5588 # there is no qmp command, so we use the human monitor command
5589 vm_human_monitor_command
($vmid, "sendkey $key");
5594 my ($storecfg, $vmid, $skiplock) = @_;
5596 PVE
::QemuConfig-
>lock_config($vmid, sub {
5598 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5600 if (!check_running
($vmid)) {
5601 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5603 die "VM $vmid is running - destroy failed\n";
5608 # vzdump restore implementaion
5610 sub tar_archive_read_firstfile
{
5611 my $archive = shift;
5613 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5615 # try to detect archive type first
5616 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5617 die "unable to open file '$archive'\n";
5618 my $firstfile = <$fh>;
5622 die "ERROR: archive contaions no data\n" if !$firstfile;
5628 sub tar_restore_cleanup
{
5629 my ($storecfg, $statfile) = @_;
5631 print STDERR
"starting cleanup\n";
5633 if (my $fd = IO
::File-
>new($statfile, "r")) {
5634 while (defined(my $line = <$fd>)) {
5635 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5638 if ($volid =~ m
|^/|) {
5639 unlink $volid || die 'unlink failed\n';
5641 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5643 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5645 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5647 print STDERR
"unable to parse line in statfile - $line";
5654 sub restore_archive
{
5655 my ($archive, $vmid, $user, $opts) = @_;
5657 my $format = $opts->{format
};
5660 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5661 $format = 'tar' if !$format;
5663 } elsif ($archive =~ m/\.tar$/) {
5664 $format = 'tar' if !$format;
5665 } elsif ($archive =~ m/.tar.lzo$/) {
5666 $format = 'tar' if !$format;
5668 } elsif ($archive =~ m/\.vma$/) {
5669 $format = 'vma' if !$format;
5670 } elsif ($archive =~ m/\.vma\.gz$/) {
5671 $format = 'vma' if !$format;
5673 } elsif ($archive =~ m/\.vma\.lzo$/) {
5674 $format = 'vma' if !$format;
5677 $format = 'vma' if !$format; # default
5680 # try to detect archive format
5681 if ($format eq 'tar') {
5682 return restore_tar_archive
($archive, $vmid, $user, $opts);
5684 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5688 sub restore_update_config_line
{
5689 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5691 return if $line =~ m/^\#qmdump\#/;
5692 return if $line =~ m/^\#vzdump\#/;
5693 return if $line =~ m/^lock:/;
5694 return if $line =~ m/^unused\d+:/;
5695 return if $line =~ m/^parent:/;
5696 return if $line =~ m/^template:/; # restored VM is never a template
5698 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5699 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5700 # try to convert old 1.X settings
5701 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5702 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5703 my ($model, $macaddr) = split(/\=/, $devconfig);
5704 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5707 bridge
=> "vmbr$ind",
5708 macaddr
=> $macaddr,
5710 my $netstr = print_net
($net);
5712 print $outfd "net$cookie->{netcount}: $netstr\n";
5713 $cookie->{netcount
}++;
5715 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5716 my ($id, $netstr) = ($1, $2);
5717 my $net = parse_net
($netstr);
5718 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5719 $netstr = print_net
($net);
5720 print $outfd "$id: $netstr\n";
5721 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5724 my $di = parse_drive
($virtdev, $value);
5725 if (defined($di->{backup
}) && !$di->{backup
}) {
5726 print $outfd "#$line";
5727 } elsif ($map->{$virtdev}) {
5728 delete $di->{format
}; # format can change on restore
5729 $di->{file
} = $map->{$virtdev};
5730 $value = print_drive
($vmid, $di);
5731 print $outfd "$virtdev: $value\n";
5735 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5737 if ($vmgenid ne '0') {
5738 # always generate a new vmgenid if there was a valid one setup
5739 $vmgenid = generate_uuid
();
5741 print $outfd "vmgenid: $vmgenid\n";
5742 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5743 my ($uuid, $uuid_str);
5744 UUID
::generate
($uuid);
5745 UUID
::unparse
($uuid, $uuid_str);
5746 my $smbios1 = parse_smbios1
($2);
5747 $smbios1->{uuid
} = $uuid_str;
5748 print $outfd $1.print_smbios1
($smbios1)."\n";
5755 my ($cfg, $vmid) = @_;
5757 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5759 my $volid_hash = {};
5760 foreach my $storeid (keys %$info) {
5761 foreach my $item (@{$info->{$storeid}}) {
5762 next if !($item->{volid
} && $item->{size
});
5763 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5764 $volid_hash->{$item->{volid
}} = $item;
5771 sub is_volume_in_use
{
5772 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5774 my $path = PVE
::Storage
::path
($storecfg, $volid);
5776 my $scan_config = sub {
5777 my ($cref, $snapname) = @_;
5779 foreach my $key (keys %$cref) {
5780 my $value = $cref->{$key};
5781 if (is_valid_drivename
($key)) {
5782 next if $skip_drive && $key eq $skip_drive;
5783 my $drive = parse_drive
($key, $value);
5784 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5785 return 1 if $volid eq $drive->{file
};
5786 if ($drive->{file
} =~ m!^/!) {
5787 return 1 if $drive->{file
} eq $path;
5789 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5791 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5793 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5801 return 1 if &$scan_config($conf);
5805 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5806 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5812 sub update_disksize
{
5813 my ($vmid, $conf, $volid_hash) = @_;
5816 my $prefix = "VM $vmid:";
5818 # used and unused disks
5819 my $referenced = {};
5821 # Note: it is allowed to define multiple storages with same path (alias), so
5822 # we need to check both 'volid' and real 'path' (two different volid can point
5823 # to the same path).
5825 my $referencedpath = {};
5828 foreach my $opt (keys %$conf) {
5829 if (is_valid_drivename
($opt)) {
5830 my $drive = parse_drive
($opt, $conf->{$opt});
5831 my $volid = $drive->{file
};
5834 $referenced->{$volid} = 1;
5835 if ($volid_hash->{$volid} &&
5836 (my $path = $volid_hash->{$volid}->{path
})) {
5837 $referencedpath->{$path} = 1;
5840 next if drive_is_cdrom
($drive);
5841 next if !$volid_hash->{$volid};
5843 $drive->{size
} = $volid_hash->{$volid}->{size
};
5844 my $new = print_drive
($vmid, $drive);
5845 if ($new ne $conf->{$opt}) {
5847 $conf->{$opt} = $new;
5848 print "$prefix update disk '$opt' information.\n";
5853 # remove 'unusedX' entry if volume is used
5854 foreach my $opt (keys %$conf) {
5855 next if $opt !~ m/^unused\d+$/;
5856 my $volid = $conf->{$opt};
5857 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5858 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5859 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5861 delete $conf->{$opt};
5864 $referenced->{$volid} = 1;
5865 $referencedpath->{$path} = 1 if $path;
5868 foreach my $volid (sort keys %$volid_hash) {
5869 next if $volid =~ m/vm-$vmid-state-/;
5870 next if $referenced->{$volid};
5871 my $path = $volid_hash->{$volid}->{path
};
5872 next if !$path; # just to be sure
5873 next if $referencedpath->{$path};
5875 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5876 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5877 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5884 my ($vmid, $nolock, $dryrun) = @_;
5886 my $cfg = PVE
::Storage
::config
();
5888 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5889 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5890 foreach my $stor (keys %{$cfg->{ids
}}) {
5891 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5894 print "rescan volumes...\n";
5895 my $volid_hash = scan_volids
($cfg, $vmid);
5897 my $updatefn = sub {
5900 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5902 PVE
::QemuConfig-
>check_lock($conf);
5905 foreach my $volid (keys %$volid_hash) {
5906 my $info = $volid_hash->{$volid};
5907 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5910 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5912 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5915 if (defined($vmid)) {
5919 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5922 my $vmlist = config_list
();
5923 foreach my $vmid (keys %$vmlist) {
5927 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5933 sub restore_vma_archive
{
5934 my ($archive, $vmid, $user, $opts, $comp) = @_;
5936 my $readfrom = $archive;
5938 my $cfg = PVE
::Storage
::config
();
5940 my $bwlimit = $opts->{bwlimit
};
5942 my $dbg_cmdstring = '';
5943 my $add_pipe = sub {
5945 push @$commands, $cmd;
5946 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5947 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5952 if ($archive eq '-') {
5955 # If we use a backup from a PVE defined storage we also consider that
5956 # storage's rate limit:
5957 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5958 if (defined($volid)) {
5959 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5960 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5962 print STDERR
"applying read rate limit: $readlimit\n";
5963 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5964 $add_pipe->($cstream);
5971 if ($comp eq 'gzip') {
5972 $cmd = ['zcat', $readfrom];
5973 } elsif ($comp eq 'lzop') {
5974 $cmd = ['lzop', '-d', '-c', $readfrom];
5976 die "unknown compression method '$comp'\n";
5981 my $tmpdir = "/var/tmp/vzdumptmp$$";
5984 # disable interrupts (always do cleanups)
5988 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5990 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5991 POSIX
::mkfifo
($mapfifo, 0600);
5994 my $openfifo = sub {
5995 open($fifofh, '>', $mapfifo) || die $!;
5998 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6005 my $rpcenv = PVE
::RPCEnvironment
::get
();
6007 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6008 my $tmpfn = "$conffile.$$.tmp";
6010 # Note: $oldconf is undef if VM does not exists
6011 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6012 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6016 my $print_devmap = sub {
6017 my $virtdev_hash = {};
6019 my $cfgfn = "$tmpdir/qemu-server.conf";
6021 # we can read the config - that is already extracted
6022 my $fh = IO
::File-
>new($cfgfn, "r") ||
6023 "unable to read qemu-server.conf - $!\n";
6025 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6027 my $pve_firewall_dir = '/etc/pve/firewall';
6028 mkdir $pve_firewall_dir; # make sure the dir exists
6029 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6032 while (defined(my $line = <$fh>)) {
6033 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6034 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6035 die "archive does not contain data for drive '$virtdev'\n"
6036 if !$devinfo->{$devname};
6037 if (defined($opts->{storage
})) {
6038 $storeid = $opts->{storage
} || 'local';
6039 } elsif (!$storeid) {
6042 $format = 'raw' if !$format;
6043 $devinfo->{$devname}->{devname
} = $devname;
6044 $devinfo->{$devname}->{virtdev
} = $virtdev;
6045 $devinfo->{$devname}->{format
} = $format;
6046 $devinfo->{$devname}->{storeid
} = $storeid;
6048 # check permission on storage
6049 my $pool = $opts->{pool
}; # todo: do we need that?
6050 if ($user ne 'root@pam') {
6051 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6054 $storage_limits{$storeid} = $bwlimit;
6056 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6060 foreach my $key (keys %storage_limits) {
6061 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6063 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6064 $storage_limits{$key} = $limit * 1024;
6067 foreach my $devname (keys %$devinfo) {
6068 die "found no device mapping information for device '$devname'\n"
6069 if !$devinfo->{$devname}->{virtdev
};
6072 # create empty/temp config
6074 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6075 foreach_drive
($oldconf, sub {
6076 my ($ds, $drive) = @_;
6078 return if drive_is_cdrom
($drive);
6080 my $volid = $drive->{file
};
6082 return if !$volid || $volid =~ m
|^/|;
6084 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6085 return if !$path || !$owner || ($owner != $vmid);
6087 # Note: only delete disk we want to restore
6088 # other volumes will become unused
6089 if ($virtdev_hash->{$ds}) {
6090 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6097 # delete vmstate files
6098 # since after the restore we have no snapshots anymore
6099 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6100 my $snap = $oldconf->{snapshots
}->{$snapname};
6101 if ($snap->{vmstate
}) {
6102 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6111 foreach my $virtdev (sort keys %$virtdev_hash) {
6112 my $d = $virtdev_hash->{$virtdev};
6113 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6114 my $storeid = $d->{storeid
};
6115 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6118 if (my $limit = $storage_limits{$storeid}) {
6119 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6122 # test if requested format is supported
6123 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6124 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6125 $d->{format
} = $defFormat if !$supported;
6127 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6128 $d->{format
}, undef, $alloc_size);
6129 print STDERR
"new volume ID is '$volid'\n";
6130 $d->{volid
} = $volid;
6131 my $path = PVE
::Storage
::path
($cfg, $volid);
6133 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6135 my $write_zeros = 1;
6136 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6140 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6142 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6143 $map->{$virtdev} = $volid;
6146 $fh->seek(0, 0) || die "seek failed - $!\n";
6148 my $outfd = new IO
::File
($tmpfn, "w") ||
6149 die "unable to write config for VM $vmid\n";
6151 my $cookie = { netcount
=> 0 };
6152 while (defined(my $line = <$fh>)) {
6153 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6166 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6167 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6169 $oldtimeout = alarm($timeout);
6176 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6177 my ($dev_id, $size, $devname) = ($1, $2, $3);
6178 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6179 } elsif ($line =~ m/^CTIME: /) {
6180 # we correctly received the vma config, so we can disable
6181 # the timeout now for disk allocation (set to 10 minutes, so
6182 # that we always timeout if something goes wrong)
6185 print $fifofh "done\n";
6186 my $tmp = $oldtimeout || 0;
6187 $oldtimeout = undef;
6193 print "restore vma archive: $dbg_cmdstring\n";
6194 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6198 alarm($oldtimeout) if $oldtimeout;
6201 foreach my $devname (keys %$devinfo) {
6202 my $volid = $devinfo->{$devname}->{volid
};
6203 push @$vollist, $volid if $volid;
6206 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6214 foreach my $devname (keys %$devinfo) {
6215 my $volid = $devinfo->{$devname}->{volid
};
6218 if ($volid =~ m
|^/|) {
6219 unlink $volid || die 'unlink failed\n';
6221 PVE
::Storage
::vdisk_free
($cfg, $volid);
6223 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6225 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6232 rename($tmpfn, $conffile) ||
6233 die "unable to commit configuration file '$conffile'\n";
6235 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6237 eval { rescan
($vmid, 1); };
6241 sub restore_tar_archive
{
6242 my ($archive, $vmid, $user, $opts) = @_;
6244 if ($archive ne '-') {
6245 my $firstfile = tar_archive_read_firstfile
($archive);
6246 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6247 if $firstfile ne 'qemu-server.conf';
6250 my $storecfg = PVE
::Storage
::config
();
6252 # destroy existing data - keep empty config
6253 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6254 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6256 my $tocmd = "/usr/lib/qemu-server/qmextract";
6258 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6259 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6260 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6261 $tocmd .= ' --info' if $opts->{info
};
6263 # tar option "xf" does not autodetect compression when read from STDIN,
6264 # so we pipe to zcat
6265 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6266 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6268 my $tmpdir = "/var/tmp/vzdumptmp$$";
6271 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6272 local $ENV{VZDUMP_VMID
} = $vmid;
6273 local $ENV{VZDUMP_USER
} = $user;
6275 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6276 my $tmpfn = "$conffile.$$.tmp";
6278 # disable interrupts (always do cleanups)
6282 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6290 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6292 if ($archive eq '-') {
6293 print "extracting archive from STDIN\n";
6294 run_command
($cmd, input
=> "<&STDIN");
6296 print "extracting archive '$archive'\n";
6300 return if $opts->{info
};
6304 my $statfile = "$tmpdir/qmrestore.stat";
6305 if (my $fd = IO
::File-
>new($statfile, "r")) {
6306 while (defined (my $line = <$fd>)) {
6307 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6308 $map->{$1} = $2 if $1;
6310 print STDERR
"unable to parse line in statfile - $line\n";
6316 my $confsrc = "$tmpdir/qemu-server.conf";
6318 my $srcfd = new IO
::File
($confsrc, "r") ||
6319 die "unable to open file '$confsrc'\n";
6321 my $outfd = new IO
::File
($tmpfn, "w") ||
6322 die "unable to write config for VM $vmid\n";
6324 my $cookie = { netcount
=> 0 };
6325 while (defined (my $line = <$srcfd>)) {
6326 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6338 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6345 rename $tmpfn, $conffile ||
6346 die "unable to commit configuration file '$conffile'\n";
6348 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6350 eval { rescan
($vmid, 1); };
6354 sub foreach_storage_used_by_vm
{
6355 my ($conf, $func) = @_;
6359 foreach_drive
($conf, sub {
6360 my ($ds, $drive) = @_;
6361 return if drive_is_cdrom
($drive);
6363 my $volid = $drive->{file
};
6365 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6366 $sidhash->{$sid} = $sid if $sid;
6369 foreach my $sid (sort keys %$sidhash) {
6374 sub do_snapshots_with_qemu
{
6375 my ($storecfg, $volid) = @_;
6377 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6379 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6380 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6384 if ($volid =~ m/\.(qcow2|qed)$/){
6391 sub qga_check_running
{
6392 my ($vmid, $nowarn) = @_;
6394 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6396 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6402 sub template_create
{
6403 my ($vmid, $conf, $disk) = @_;
6405 my $storecfg = PVE
::Storage
::config
();
6407 foreach_drive
($conf, sub {
6408 my ($ds, $drive) = @_;
6410 return if drive_is_cdrom
($drive);
6411 return if $disk && $ds ne $disk;
6413 my $volid = $drive->{file
};
6414 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6416 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6417 $drive->{file
} = $voliddst;
6418 $conf->{$ds} = print_drive
($vmid, $drive);
6419 PVE
::QemuConfig-
>write_config($vmid, $conf);
6423 sub qemu_img_convert
{
6424 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6426 my $storecfg = PVE
::Storage
::config
();
6427 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6428 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6430 if ($src_storeid && $dst_storeid) {
6432 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6434 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6435 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6437 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6438 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6440 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6441 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6444 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6445 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6446 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6447 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6448 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6449 if ($is_zero_initialized) {
6450 push @$cmd, "zeroinit:$dst_path";
6452 push @$cmd, $dst_path;
6457 if($line =~ m/\((\S+)\/100\
%\)/){
6459 my $transferred = int($size * $percent / 100);
6460 my $remaining = $size - $transferred;
6462 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6467 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6469 die "copy failed: $err" if $err;
6473 sub qemu_img_format
{
6474 my ($scfg, $volname) = @_;
6476 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6483 sub qemu_drive_mirror
{
6484 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6486 $jobs = {} if !$jobs;
6490 $jobs->{"drive-$drive"} = {};
6492 if ($dst_volid =~ /^nbd:/) {
6493 $qemu_target = $dst_volid;
6496 my $storecfg = PVE
::Storage
::config
();
6497 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6499 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6501 $format = qemu_img_format
($dst_scfg, $dst_volname);
6503 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6505 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6508 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6509 $opts->{format
} = $format if $format;
6511 print "drive mirror is starting for drive-$drive\n";
6513 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6516 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6517 die "mirroring error: $err";
6520 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6523 sub qemu_drive_mirror_monitor
{
6524 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6527 my $err_complete = 0;
6530 die "storage migration timed out\n" if $err_complete > 300;
6532 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6534 my $running_mirror_jobs = {};
6535 foreach my $stat (@$stats) {
6536 next if $stat->{type
} ne 'mirror';
6537 $running_mirror_jobs->{$stat->{device
}} = $stat;
6540 my $readycounter = 0;
6542 foreach my $job (keys %$jobs) {
6544 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6545 print "$job : finished\n";
6546 delete $jobs->{$job};
6550 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6552 my $busy = $running_mirror_jobs->{$job}->{busy
};
6553 my $ready = $running_mirror_jobs->{$job}->{ready
};
6554 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6555 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6556 my $remaining = $total - $transferred;
6557 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6559 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6562 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6565 last if scalar(keys %$jobs) == 0;
6567 if ($readycounter == scalar(keys %$jobs)) {
6568 print "all mirroring jobs are ready \n";
6569 last if $skipcomplete; #do the complete later
6571 if ($vmiddst && $vmiddst != $vmid) {
6572 my $agent_running = $qga && qga_check_running
($vmid);
6573 if ($agent_running) {
6574 print "freeze filesystem\n";
6575 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6577 print "suspend vm\n";
6578 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6581 # if we clone a disk for a new target vm, we don't switch the disk
6582 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6584 if ($agent_running) {
6585 print "unfreeze filesystem\n";
6586 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6588 print "resume vm\n";
6589 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6595 foreach my $job (keys %$jobs) {
6596 # try to switch the disk if source and destination are on the same guest
6597 print "$job: Completing block job...\n";
6599 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6600 if ($@ =~ m/cannot be completed/) {
6601 print "$job: Block job cannot be completed, try again.\n";
6604 print "$job: Completed successfully.\n";
6605 $jobs->{$job}->{complete
} = 1;
6616 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6617 die "mirroring error: $err";
6622 sub qemu_blockjobs_cancel
{
6623 my ($vmid, $jobs) = @_;
6625 foreach my $job (keys %$jobs) {
6626 print "$job: Cancelling block job\n";
6627 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6628 $jobs->{$job}->{cancel
} = 1;
6632 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6634 my $running_jobs = {};
6635 foreach my $stat (@$stats) {
6636 $running_jobs->{$stat->{device
}} = $stat;
6639 foreach my $job (keys %$jobs) {
6641 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6642 print "$job: Done.\n";
6643 delete $jobs->{$job};
6647 last if scalar(keys %$jobs) == 0;
6654 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6655 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6660 print "create linked clone of drive $drivename ($drive->{file})\n";
6661 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6662 push @$newvollist, $newvolid;
6665 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6666 $storeid = $storage if $storage;
6668 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6669 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6671 print "create full clone of drive $drivename ($drive->{file})\n";
6673 if (drive_is_cloudinit
($drive)) {
6674 $name = "vm-$newvmid-cloudinit";
6676 # cloudinit only supports raw and qcow2 atm:
6677 if ($dst_format eq 'qcow2') {
6679 } elsif ($dst_format ne 'raw') {
6680 die "clone: unhandled format for cloudinit image\n";
6683 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6684 push @$newvollist, $newvolid;
6686 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6688 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6689 if (!$running || $snapname) {
6690 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6693 my $kvmver = get_running_qemu_version
($vmid);
6694 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6695 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6696 if $drive->{iothread
};
6699 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6703 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6706 $disk->{format
} = undef;
6707 $disk->{file
} = $newvolid;
6708 $disk->{size
} = $size;
6713 # this only works if VM is running
6714 sub get_current_qemu_machine
{
6717 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6718 my $res = vm_qmp_command
($vmid, $cmd);
6720 my ($current, $default);
6721 foreach my $e (@$res) {
6722 $default = $e->{name
} if $e->{'is-default'};
6723 $current = $e->{name
} if $e->{'is-current'};
6726 # fallback to the default machine if current is not supported by qemu
6727 return $current || $default || 'pc';
6730 sub get_running_qemu_version
{
6732 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6733 my $res = vm_qmp_command
($vmid, $cmd);
6734 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6737 sub qemu_machine_feature_enabled
{
6738 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6743 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6745 $current_major = $3;
6746 $current_minor = $4;
6748 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6750 $current_major = $1;
6751 $current_minor = $2;
6754 return 1 if $current_major > $version_major ||
6755 ($current_major == $version_major &&
6756 $current_minor >= $version_minor);
6759 sub qemu_machine_pxe
{
6760 my ($vmid, $conf, $machine) = @_;
6762 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6764 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6771 sub qemu_use_old_bios_files
{
6772 my ($machine_type) = @_;
6774 return if !$machine_type;
6776 my $use_old_bios_files = undef;
6778 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6780 $use_old_bios_files = 1;
6782 my $kvmver = kvm_user_version
();
6783 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6784 # load new efi bios files on migration. So this hack is required to allow
6785 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6786 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6787 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6790 return ($use_old_bios_files, $machine_type);
6793 sub create_efidisk
($$$$$) {
6794 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6796 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6797 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6799 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6800 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6801 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6803 my $path = PVE
::Storage
::path
($storecfg, $volid);
6805 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6807 die "Copying EFI vars image failed: $@" if $@;
6809 return ($volid, $vars_size);
6812 sub vm_iothreads_list
{
6815 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6818 foreach my $iothread (@$res) {
6819 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6826 my ($conf, $drive) = @_;
6830 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6832 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6838 my $controller = int($drive->{index} / $maxdev);
6839 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6841 return ($maxdev, $controller, $controller_prefix);
6844 sub add_hyperv_enlightenments
{
6845 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
6847 return if $winversion < 6;
6848 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6850 if ($gpu_passthrough || defined($hv_vendor_id)) {
6851 $hv_vendor_id //= 'proxmox';
6852 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
6855 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6856 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6857 push @$cpuFlags , 'hv_vapic';
6858 push @$cpuFlags , 'hv_time';
6860 push @$cpuFlags , 'hv_spinlocks=0xffff';
6863 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6864 push @$cpuFlags , 'hv_reset';
6865 push @$cpuFlags , 'hv_vpindex';
6866 push @$cpuFlags , 'hv_runtime';
6869 if ($winversion >= 7) {
6870 push @$cpuFlags , 'hv_relaxed';
6872 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6873 push @$cpuFlags , 'hv_synic';
6874 push @$cpuFlags , 'hv_stimer';
6879 sub windows_version
{
6882 return 0 if !$ostype;
6886 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6888 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6890 } elsif ($ostype =~ m/^win(\d+)$/) {
6897 sub resolve_dst_disk_format
{
6898 my ($storecfg, $storeid, $src_volname, $format) = @_;
6899 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6902 # if no target format is specified, use the source disk format as hint
6904 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6905 $format = qemu_img_format
($scfg, $src_volname);
6911 # test if requested format is supported - else use default
6912 my $supported = grep { $_ eq $format } @$validFormats;
6913 $format = $defFormat if !$supported;
6917 sub resolve_first_disk
{
6919 my @disks = PVE
::QemuServer
::valid_drive_names
();
6921 foreach my $ds (reverse @disks) {
6922 next if !$conf->{$ds};
6923 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6924 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6931 my ($uuid, $uuid_str);
6932 UUID
::generate
($uuid);
6933 UUID
::unparse
($uuid, $uuid_str);
6937 sub generate_smbios1_uuid
{
6938 return "uuid=".generate_uuid
();
6944 vm_mon_cmd
($vmid, 'nbd-server-stop');
6947 # bash completion helper
6949 sub complete_backup_archives
{
6950 my ($cmdname, $pname, $cvalue) = @_;
6952 my $cfg = PVE
::Storage
::config
();
6956 if ($cvalue =~ m/^([^:]+):/) {
6960 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6963 foreach my $id (keys %$data) {
6964 foreach my $item (@{$data->{$id}}) {
6965 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6966 push @$res, $item->{volid
} if defined($item->{volid
});
6973 my $complete_vmid_full = sub {
6976 my $idlist = vmstatus
();
6980 foreach my $id (keys %$idlist) {
6981 my $d = $idlist->{$id};
6982 if (defined($running)) {
6983 next if $d->{template
};
6984 next if $running && $d->{status
} ne 'running';
6985 next if !$running && $d->{status
} eq 'running';
6994 return &$complete_vmid_full();
6997 sub complete_vmid_stopped
{
6998 return &$complete_vmid_full(0);
7001 sub complete_vmid_running
{
7002 return &$complete_vmid_full(1);
7005 sub complete_storage
{
7007 my $cfg = PVE
::Storage
::config
();
7008 my $ids = $cfg->{ids
};
7011 foreach my $sid (keys %$ids) {
7012 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7013 next if !$ids->{$sid}->{content
}->{images
};