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 $pcisysfs = "/sys/bus/pci";
124 my $cpu_vendor_list = {
126 486 => 'GenuineIntel',
127 pentium
=> 'GenuineIntel',
128 pentium2
=> 'GenuineIntel',
129 pentium3
=> 'GenuineIntel',
130 coreduo
=> 'GenuineIntel',
131 core2duo
=> 'GenuineIntel',
132 Conroe
=> 'GenuineIntel',
133 Penryn
=> 'GenuineIntel',
134 Nehalem
=> 'GenuineIntel',
135 'Nehalem-IBRS' => 'GenuineIntel',
136 Westmere
=> 'GenuineIntel',
137 'Westmere-IBRS' => 'GenuineIntel',
138 SandyBridge
=> 'GenuineIntel',
139 'SandyBridge-IBRS' => 'GenuineIntel',
140 IvyBridge
=> 'GenuineIntel',
141 'IvyBridge-IBRS' => 'GenuineIntel',
142 Haswell
=> 'GenuineIntel',
143 'Haswell-IBRS' => 'GenuineIntel',
144 'Haswell-noTSX' => 'GenuineIntel',
145 'Haswell-noTSX-IBRS' => 'GenuineIntel',
146 Broadwell
=> 'GenuineIntel',
147 'Broadwell-IBRS' => 'GenuineIntel',
148 'Broadwell-noTSX' => 'GenuineIntel',
149 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
150 'Skylake-Client' => 'GenuineIntel',
151 'Skylake-Client-IBRS' => 'GenuineIntel',
152 'Skylake-Server' => 'GenuineIntel',
153 'Skylake-Server-IBRS' => 'GenuineIntel',
156 athlon
=> 'AuthenticAMD',
157 phenom
=> 'AuthenticAMD',
158 Opteron_G1
=> 'AuthenticAMD',
159 Opteron_G2
=> 'AuthenticAMD',
160 Opteron_G3
=> 'AuthenticAMD',
161 Opteron_G4
=> 'AuthenticAMD',
162 Opteron_G5
=> 'AuthenticAMD',
163 EPYC
=> 'AuthenticAMD',
164 'EPYC-IBPB' => 'AuthenticAMD',
166 # generic types, use vendor from host node
175 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
179 description
=> "Emulated CPU type.",
181 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
186 description
=> "Do not identify as a KVM virtual machine.",
192 description
=> "List of additional CPU flags separated by ';'."
193 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
194 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
195 format_description
=> '+FLAG[;-FLAG...]',
197 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
206 enum
=> [qw(i6300esb ib700)],
207 description
=> "Watchdog type to emulate.",
208 default => 'i6300esb',
213 enum
=> [qw(reset shutdown poweroff pause debug none)],
214 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
218 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
222 description
=> "Enable/disable Qemu GuestAgent.",
227 fstrim_cloned_disks
=> {
228 description
=> "Run fstrim after cloning/moving a disk.",
237 description
=> "Select the VGA type.",
242 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 serial0 serial1 serial2 serial3 std virtio vmware)],
245 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
257 description
=> "Specifies whether a VM will be started during system bootup.",
263 description
=> "Automatic restart after crash (currently ignored).",
268 type
=> 'string', format
=> 'pve-hotplug-features',
269 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'.",
270 default => 'network,disk,usb',
275 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
281 description
=> "Lock/unlock the VM.",
282 enum
=> [qw(migrate backup snapshot rollback)],
287 description
=> "Limit of CPU usage.",
288 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.",
296 description
=> "CPU weight for a VM.",
297 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.",
305 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
312 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
318 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.",
326 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
327 "It should not be necessary to set it.",
328 enum
=> PVE
::Tools
::kvmkeymaplist
(),
333 type
=> 'string', format
=> 'dns-name',
334 description
=> "Set a name for the VM. Only used on the configuration web interface.",
339 description
=> "SCSI controller model",
340 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
346 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
351 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
352 description
=> "Specify guest operating system.",
353 verbose_description
=> <<EODESC,
354 Specify guest operating system. This is used to enable special
355 optimization/features for specific operating systems:
358 other;; unspecified OS
359 wxp;; Microsoft Windows XP
360 w2k;; Microsoft Windows 2000
361 w2k3;; Microsoft Windows 2003
362 w2k8;; Microsoft Windows 2008
363 wvista;; Microsoft Windows Vista
364 win7;; Microsoft Windows 7
365 win8;; Microsoft Windows 8/2012/2012r2
366 win10;; Microsoft Windows 10/2016
367 l24;; Linux 2.4 Kernel
368 l26;; Linux 2.6/3.X Kernel
369 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
375 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
376 pattern
=> '[acdn]{1,4}',
381 type
=> 'string', format
=> 'pve-qm-bootdisk',
382 description
=> "Enable booting from specified disk.",
383 pattern
=> '(ide|sata|scsi|virtio)\d+',
388 description
=> "The number of CPUs. Please use option -sockets instead.",
395 description
=> "The number of CPU sockets.",
402 description
=> "The number of cores per socket.",
409 description
=> "Enable/disable NUMA.",
415 description
=> "Enable/disable hugepages memory.",
416 enum
=> [qw(any 2 1024)],
421 description
=> "Number of hotplugged vcpus.",
428 description
=> "Enable/disable ACPI.",
433 description
=> "Enable/disable Qemu GuestAgent and its properties.",
435 format
=> $agent_fmt,
440 description
=> "Enable/disable KVM hardware virtualization.",
446 description
=> "Enable/disable time drift fix.",
452 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
457 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
461 type
=> 'string', format
=> $vga_fmt,
462 description
=> "Configure the VGA hardware.",
463 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
464 "high resolution modes (>= 1280x1024x16) you may need to increase " .
465 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
466 "is 'std' for all OS types besides some Windows versions (XP and " .
467 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
468 "display server. For win* OS you can select how many independent " .
469 "displays you want, Linux guests can add displays them self.\n".
470 "You can also run without any graphic card, using a serial device as terminal.",
474 type
=> 'string', format
=> 'pve-qm-watchdog',
475 description
=> "Create a virtual hardware watchdog device.",
476 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
477 " (by a guest action), the watchdog must be periodically polled " .
478 "by an agent inside the guest or else the watchdog will reset " .
479 "the guest (or execute the respective action specified)",
484 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
485 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'.",
486 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
489 startup
=> get_standard_option
('pve-startup-order'),
493 description
=> "Enable/disable Template.",
499 description
=> "Arbitrary arguments passed to kvm.",
500 verbose_description
=> <<EODESCR,
501 Arbitrary arguments passed to kvm, for example:
503 args: -no-reboot -no-hpet
505 NOTE: this option is for experts only.
512 description
=> "Enable/disable the USB tablet device.",
513 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
514 "usually needed to allow absolute mouse positioning with VNC. " .
515 "Else the mouse runs out of sync with normal VNC clients. " .
516 "If you're running lots of console-only guests on one host, " .
517 "you may consider disabling this to save some context switches. " .
518 "This is turned off by default if you use spice (-vga=qxl).",
523 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
527 migrate_downtime
=> {
530 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
536 type
=> 'string', format
=> 'pve-qm-ide',
537 typetext
=> '<volume>',
538 description
=> "This is an alias for option -ide2",
542 description
=> "Emulated CPU type.",
546 parent
=> get_standard_option
('pve-snapshot-name', {
548 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
552 description
=> "Timestamp for snapshots.",
558 type
=> 'string', format
=> 'pve-volume-id',
559 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
561 vmstatestorage
=> get_standard_option
('pve-storage-id', {
562 description
=> "Default storage for VM state volumes/files.",
565 runningmachine
=> get_standard_option
('pve-qemu-machine', {
566 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
568 machine
=> get_standard_option
('pve-qemu-machine'),
570 description
=> "Virtual processor architecture. Defaults to the host.",
573 enum
=> [qw(x86_64 aarch64)],
576 description
=> "Specify SMBIOS type 1 fields.",
577 type
=> 'string', format
=> 'pve-qm-smbios1',
584 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
590 enum
=> [ qw(seabios ovmf) ],
591 description
=> "Select BIOS implementation.",
592 default => 'seabios',
596 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
597 format_description
=> 'UUID',
598 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
599 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
600 " 128-bit integer value identifier to the guest OS. This allows to".
601 " notify the guest operating system when the virtual machine is".
602 " executed with a different configuration (e.g. snapshot execution".
603 " or creation from a template). The guest operating system notices".
604 " the change, and is then able to react as appropriate by marking".
605 " its copies of distributed databases as dirty, re-initializing its".
606 " random number generator, etc.\n".
607 "Note that auto-creation only works when done throug API/CLI create".
608 " or update methods, but not when manually editing the config file.",
609 default => "1 (autogenerated)",
614 my $confdesc_cloudinit = {
618 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.',
619 enum
=> ['configdrive2', 'nocloud'],
624 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
629 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.',
634 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.",
638 type
=> 'string', format
=> 'address-list',
639 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.",
644 format
=> 'urlencoded',
645 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
649 # what about other qemu settings ?
651 #machine => 'string',
664 ##soundhw => 'string',
666 while (my ($k, $v) = each %$confdesc) {
667 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
670 my $MAX_IDE_DISKS = 4;
671 my $MAX_SCSI_DISKS = 14;
672 my $MAX_VIRTIO_DISKS = 16;
673 my $MAX_SATA_DISKS = 6;
674 my $MAX_USB_DEVICES = 5;
676 my $MAX_UNUSED_DISKS = 256;
677 my $MAX_HOSTPCI_DEVICES = 4;
678 my $MAX_SERIAL_PORTS = 4;
679 my $MAX_PARALLEL_PORTS = 3;
685 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
686 description
=> "CPUs accessing this NUMA node.",
687 format_description
=> "id[-id];...",
691 description
=> "Amount of memory this NUMA node provides.",
696 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
697 description
=> "Host NUMA nodes to use.",
698 format_description
=> "id[-id];...",
703 enum
=> [qw(preferred bind interleave)],
704 description
=> "NUMA allocation policy.",
708 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
711 type
=> 'string', format
=> $numa_fmt,
712 description
=> "NUMA topology.",
714 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
716 for (my $i = 0; $i < $MAX_NUMA; $i++) {
717 $confdesc->{"numa$i"} = $numadesc;
720 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
721 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
722 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
723 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
725 my $net_fmt_bridge_descr = <<__EOD__;
726 Bridge to attach the network device to. The Proxmox VE standard bridge
729 If you do not specify a bridge, we create a kvm user (NATed) network
730 device, which provides DHCP and DNS services. The following addresses
737 The DHCP server assign addresses to the guest starting from 10.0.2.15.
743 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
744 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
745 format_description
=> "XX:XX:XX:XX:XX:XX",
750 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'.",
751 enum
=> $nic_model_list,
754 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
757 description
=> $net_fmt_bridge_descr,
758 format_description
=> 'bridge',
763 minimum
=> 0, maximum
=> 16,
764 description
=> 'Number of packet queues to be used on the device.',
770 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
775 minimum
=> 1, maximum
=> 4094,
776 description
=> 'VLAN tag to apply to packets on this interface.',
781 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
782 description
=> 'VLAN trunks to pass through this interface.',
783 format_description
=> 'vlanid[;vlanid...]',
788 description
=> 'Whether this interface should be protected by the firewall.',
793 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
800 type
=> 'string', format
=> $net_fmt,
801 description
=> "Specify network devices.",
804 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
809 format
=> 'pve-ipv4-config',
810 format_description
=> 'IPv4Format/CIDR',
811 description
=> 'IPv4 address in CIDR format.',
818 format_description
=> 'GatewayIPv4',
819 description
=> 'Default gateway for IPv4 traffic.',
825 format
=> 'pve-ipv6-config',
826 format_description
=> 'IPv6Format/CIDR',
827 description
=> 'IPv6 address in CIDR format.',
834 format_description
=> 'GatewayIPv6',
835 description
=> 'Default gateway for IPv6 traffic.',
840 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
843 type
=> 'string', format
=> 'pve-qm-ipconfig',
844 description
=> <<'EODESCR',
845 cloud-init: Specify IP addresses and gateways for the corresponding interface.
847 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
849 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
850 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
852 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
855 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
857 for (my $i = 0; $i < $MAX_NETS; $i++) {
858 $confdesc->{"net$i"} = $netdesc;
859 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
862 foreach my $key (keys %$confdesc_cloudinit) {
863 $confdesc->{$key} = $confdesc_cloudinit->{$key};
866 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
867 sub verify_volume_id_or_qm_path
{
868 my ($volid, $noerr) = @_;
870 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
874 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
875 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
877 return undef if $noerr;
885 my %drivedesc_base = (
886 volume
=> { alias
=> 'file' },
889 format
=> 'pve-volume-id-or-qm-path',
891 format_description
=> 'volume',
892 description
=> "The drive's backing volume.",
896 enum
=> [qw(cdrom disk)],
897 description
=> "The drive's media type.",
903 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
908 description
=> "Force the drive's physical geometry to have a specific head count.",
913 description
=> "Force the drive's physical geometry to have a specific sector count.",
918 enum
=> [qw(none lba auto)],
919 description
=> "Force disk geometry bios translation mode.",
924 description
=> "Controls qemu's snapshot mode feature."
925 . " If activated, changes made to the disk are temporary and will"
926 . " be discarded when the VM is shutdown.",
931 enum
=> [qw(none writethrough writeback unsafe directsync)],
932 description
=> "The drive's cache mode",
935 format
=> get_standard_option
('pve-qm-image-format'),
938 format
=> 'disk-size',
939 format_description
=> 'DiskSize',
940 description
=> "Disk size. This is purely informational and has no effect.",
945 description
=> "Whether the drive should be included when making backups.",
950 description
=> 'Whether the drive should considered for replication jobs.',
956 enum
=> [qw(ignore report stop)],
957 description
=> 'Read error action.',
962 enum
=> [qw(enospc ignore report stop)],
963 description
=> 'Write error action.',
968 enum
=> [qw(native threads)],
969 description
=> 'AIO type to use.',
974 enum
=> [qw(ignore on)],
975 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
980 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
985 format
=> 'urlencoded',
986 format_description
=> 'serial',
987 maxLength
=> 20*3, # *3 since it's %xx url enoded
988 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
993 description
=> 'Mark this locally-managed volume as available on all nodes',
994 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!",
1000 my %iothread_fmt = ( iothread
=> {
1002 description
=> "Whether to use iothreads for this drive",
1009 format
=> 'urlencoded',
1010 format_description
=> 'model',
1011 maxLength
=> 40*3, # *3 since it's %xx url enoded
1012 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1020 description
=> "Number of queues.",
1026 my %scsiblock_fmt = (
1029 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",
1038 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1043 my $add_throttle_desc = sub {
1044 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1047 format_description
=> $unit,
1048 description
=> "Maximum $what in $longunit.",
1051 $d->{minimum
} = $minimum if defined($minimum);
1052 $drivedesc_base{$key} = $d;
1054 # throughput: (leaky bucket)
1055 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1056 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1057 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1058 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1059 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1060 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1061 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1062 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1063 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1065 # pools: (pool of IO before throttling starts taking effect)
1066 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1067 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1068 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1069 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1070 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1071 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1074 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1075 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1076 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1077 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1078 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1079 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1082 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1083 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1084 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1085 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1092 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1096 type
=> 'string', format
=> $ide_fmt,
1097 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1099 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1110 type
=> 'string', format
=> $scsi_fmt,
1111 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1113 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1121 type
=> 'string', format
=> $sata_fmt,
1122 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1124 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1132 type
=> 'string', format
=> $virtio_fmt,
1133 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1135 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1137 my $alldrive_fmt = {
1147 volume
=> { alias
=> 'file' },
1150 format
=> 'pve-volume-id-or-qm-path',
1152 format_description
=> 'volume',
1153 description
=> "The drive's backing volume.",
1155 format
=> get_standard_option
('pve-qm-image-format'),
1158 format
=> 'disk-size',
1159 format_description
=> 'DiskSize',
1160 description
=> "Disk size. This is purely informational and has no effect.",
1165 my $efidisk_desc = {
1167 type
=> 'string', format
=> $efidisk_fmt,
1168 description
=> "Configure a Disk for storing EFI vars",
1171 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1176 type
=> 'string', format
=> 'pve-qm-usb-device',
1177 format_description
=> 'HOSTUSBDEVICE|spice',
1178 description
=> <<EODESCR,
1179 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1181 'bus-port(.port)*' (decimal numbers) or
1182 'vendor_id:product_id' (hexadeciaml numbers) or
1185 You can use the 'lsusb -t' command to list existing usb devices.
1187 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1189 The value 'spice' can be used to add a usb redirection devices for spice.
1195 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).",
1202 type
=> 'string', format
=> $usb_fmt,
1203 description
=> "Configure an USB device (n is 0 to 4).",
1205 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1207 # NOTE: the match-groups of this regex are used in parse_hostpci
1208 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1213 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1214 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1215 description
=> <<EODESCR,
1216 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1217 of PCI virtual functions of the host. HOSTPCIID syntax is:
1219 'bus:dev.func' (hexadecimal numbers)
1221 You can us the 'lspci' command to list existing PCI devices.
1226 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1232 pattern
=> '[^,;]+',
1233 format_description
=> 'string',
1234 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1239 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1245 description
=> "Enable vfio-vga device support.",
1250 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1254 type
=> 'string', format
=> 'pve-qm-hostpci',
1255 description
=> "Map host PCI devices into guest.",
1256 verbose_description
=> <<EODESCR,
1257 Map host PCI devices into guest.
1259 NOTE: This option allows direct access to host hardware. So it is no longer
1260 possible to migrate such machines - use with special care.
1262 CAUTION: Experimental! User reported problems with this option.
1265 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1270 pattern
=> '(/dev/.+|socket)',
1271 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1272 verbose_description
=> <<EODESCR,
1273 Create a serial device inside the VM (n is 0 to 3), and pass through a
1274 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1275 host side (use 'qm terminal' to open a terminal connection).
1277 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1279 CAUTION: Experimental! User reported problems with this option.
1286 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1287 description
=> "Map host parallel devices (n is 0 to 2).",
1288 verbose_description
=> <<EODESCR,
1289 Map host parallel devices (n is 0 to 2).
1291 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1293 CAUTION: Experimental! User reported problems with this option.
1297 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1298 $confdesc->{"parallel$i"} = $paralleldesc;
1301 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1302 $confdesc->{"serial$i"} = $serialdesc;
1305 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1306 $confdesc->{"hostpci$i"} = $hostpcidesc;
1309 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1310 $drivename_hash->{"ide$i"} = 1;
1311 $confdesc->{"ide$i"} = $idedesc;
1314 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1315 $drivename_hash->{"sata$i"} = 1;
1316 $confdesc->{"sata$i"} = $satadesc;
1319 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1320 $drivename_hash->{"scsi$i"} = 1;
1321 $confdesc->{"scsi$i"} = $scsidesc ;
1324 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1325 $drivename_hash->{"virtio$i"} = 1;
1326 $confdesc->{"virtio$i"} = $virtiodesc;
1329 $drivename_hash->{efidisk0
} = 1;
1330 $confdesc->{efidisk0
} = $efidisk_desc;
1332 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1333 $confdesc->{"usb$i"} = $usbdesc;
1338 type
=> 'string', format
=> 'pve-volume-id',
1339 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1342 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1343 $confdesc->{"unused$i"} = $unuseddesc;
1346 my $kvm_api_version = 0;
1349 return $kvm_api_version if $kvm_api_version;
1351 open my $fh, '<', '/dev/kvm'
1354 # 0xae00 => KVM_GET_API_VERSION
1355 $kvm_api_version = ioctl($fh, 0xae00, 0);
1357 return $kvm_api_version;
1360 my $kvm_user_version;
1362 sub kvm_user_version
{
1364 return $kvm_user_version if $kvm_user_version;
1366 $kvm_user_version = 'unknown';
1370 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1371 $kvm_user_version = $2;
1375 eval { run_command
("kvm -version", outfunc
=> $code); };
1378 return $kvm_user_version;
1382 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1384 sub valid_drive_names
{
1385 # order is important - used to autoselect boot disk
1386 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1387 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1388 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1389 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1393 sub is_valid_drivename
{
1396 return defined($drivename_hash->{$dev});
1401 return defined($confdesc->{$key});
1405 return $nic_model_list;
1408 sub os_list_description
{
1412 wxp
=> 'Windows XP',
1413 w2k
=> 'Windows 2000',
1414 w2k3
=>, 'Windows 2003',
1415 w2k8
=> 'Windows 2008',
1416 wvista
=> 'Windows Vista',
1417 win7
=> 'Windows 7',
1418 win8
=> 'Windows 8/2012',
1419 win10
=> 'Windows 10/2016',
1427 sub get_cdrom_path
{
1429 return $cdrom_path if $cdrom_path;
1431 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1432 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1433 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1437 my ($storecfg, $vmid, $cdrom) = @_;
1439 if ($cdrom eq 'cdrom') {
1440 return get_cdrom_path
();
1441 } elsif ($cdrom eq 'none') {
1443 } elsif ($cdrom =~ m
|^/|) {
1446 return PVE
::Storage
::path
($storecfg, $cdrom);
1450 # try to convert old style file names to volume IDs
1451 sub filename_to_volume_id
{
1452 my ($vmid, $file, $media) = @_;
1454 if (!($file eq 'none' || $file eq 'cdrom' ||
1455 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1457 return undef if $file =~ m
|/|;
1459 if ($media && $media eq 'cdrom') {
1460 $file = "local:iso/$file";
1462 $file = "local:$vmid/$file";
1469 sub verify_media_type
{
1470 my ($opt, $vtype, $media) = @_;
1475 if ($media eq 'disk') {
1477 } elsif ($media eq 'cdrom') {
1480 die "internal error";
1483 return if ($vtype eq $etype);
1485 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1488 sub cleanup_drive_path
{
1489 my ($opt, $storecfg, $drive) = @_;
1491 # try to convert filesystem paths to volume IDs
1493 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1494 ($drive->{file
} !~ m
|^/dev/.+|) &&
1495 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1496 ($drive->{file
} !~ m/^\d+$/)) {
1497 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1498 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1499 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1500 verify_media_type
($opt, $vtype, $drive->{media
});
1501 $drive->{file
} = $volid;
1504 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1507 sub parse_hotplug_features
{
1512 return $res if $data eq '0';
1514 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1516 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1517 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1520 die "invalid hotplug feature '$feature'\n";
1526 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1527 sub pve_verify_hotplug_features
{
1528 my ($value, $noerr) = @_;
1530 return $value if parse_hotplug_features
($value);
1532 return undef if $noerr;
1534 die "unable to parse hotplug option\n";
1537 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1538 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1539 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1540 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1541 # [,iothread=on][,serial=serial][,model=model]
1544 my ($key, $data) = @_;
1546 my ($interface, $index);
1548 if ($key =~ m/^([^\d]+)(\d+)$/) {
1555 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1556 : $confdesc->{$key}->{format
};
1558 warn "invalid drive key: $key\n";
1561 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1562 return undef if !$res;
1563 $res->{interface
} = $interface;
1564 $res->{index} = $index;
1567 foreach my $opt (qw(bps bps_rd bps_wr)) {
1568 if (my $bps = defined(delete $res->{$opt})) {
1569 if (defined($res->{"m$opt"})) {
1570 warn "both $opt and m$opt specified\n";
1574 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1578 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1579 for my $requirement (
1580 [mbps_max
=> 'mbps'],
1581 [mbps_rd_max
=> 'mbps_rd'],
1582 [mbps_wr_max
=> 'mbps_wr'],
1583 [miops_max
=> 'miops'],
1584 [miops_rd_max
=> 'miops_rd'],
1585 [miops_wr_max
=> 'miops_wr'],
1586 [bps_max_length
=> 'mbps_max'],
1587 [bps_rd_max_length
=> 'mbps_rd_max'],
1588 [bps_wr_max_length
=> 'mbps_wr_max'],
1589 [iops_max_length
=> 'iops_max'],
1590 [iops_rd_max_length
=> 'iops_rd_max'],
1591 [iops_wr_max_length
=> 'iops_wr_max']) {
1592 my ($option, $requires) = @$requirement;
1593 if ($res->{$option} && !$res->{$requires}) {
1594 warn "$option requires $requires\n";
1599 return undef if $error;
1601 return undef if $res->{mbps_rd
} && $res->{mbps
};
1602 return undef if $res->{mbps_wr
} && $res->{mbps
};
1603 return undef if $res->{iops_rd
} && $res->{iops
};
1604 return undef if $res->{iops_wr
} && $res->{iops
};
1606 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1607 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1608 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1609 return undef if $res->{interface
} eq 'virtio';
1612 if (my $size = $res->{size
}) {
1613 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1620 my ($vmid, $drive) = @_;
1621 my $data = { %$drive };
1622 delete $data->{$_} for qw(index interface);
1623 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1627 my($fh, $noerr) = @_;
1630 my $SG_GET_VERSION_NUM = 0x2282;
1632 my $versionbuf = "\x00" x
8;
1633 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1635 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1638 my $version = unpack("I", $versionbuf);
1639 if ($version < 30000) {
1640 die "scsi generic interface too old\n" if !$noerr;
1644 my $buf = "\x00" x
36;
1645 my $sensebuf = "\x00" x
8;
1646 my $cmd = pack("C x3 C x1", 0x12, 36);
1648 # see /usr/include/scsi/sg.h
1649 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";
1651 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1652 length($sensebuf), 0, length($buf), $buf,
1653 $cmd, $sensebuf, 6000);
1655 $ret = ioctl($fh, $SG_IO, $packet);
1657 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1661 my @res = unpack($sg_io_hdr_t, $packet);
1662 if ($res[17] || $res[18]) {
1663 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1668 (my $byte0, my $byte1, $res->{vendor
},
1669 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1671 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1672 $res->{type
} = $byte0 & 31;
1680 my $fh = IO
::File-
>new("+<$path") || return undef;
1681 my $res = scsi_inquiry
($fh, 1);
1687 sub machine_type_is_q35
{
1690 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1693 sub print_tabletdevice_full
{
1694 my ($conf, $arch) = @_;
1696 my $q35 = machine_type_is_q35
($conf);
1698 # we use uhci for old VMs because tablet driver was buggy in older qemu
1700 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1706 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1709 sub print_keyboarddevice_full
{
1710 my ($conf, $arch, $machine) = @_;
1712 return undef if $arch ne 'aarch64';
1714 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1717 sub print_drivedevice_full
{
1718 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1723 if ($drive->{interface
} eq 'virtio') {
1724 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1725 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1726 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1727 } elsif ($drive->{interface
} eq 'scsi') {
1729 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1730 my $unit = $drive->{index} % $maxdev;
1731 my $devicetype = 'hd';
1733 if (drive_is_cdrom
($drive)) {
1736 if ($drive->{file
} =~ m
|^/|) {
1737 $path = $drive->{file
};
1738 if (my $info = path_is_scsi
($path)) {
1739 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1740 $devicetype = 'block';
1741 } elsif ($info->{type
} == 1) { # tape
1742 $devicetype = 'generic';
1746 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1749 if($path =~ m/^iscsi\:\/\
//){
1750 $devicetype = 'generic';
1754 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1755 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1757 $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}";
1760 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1761 $device .= ",rotation_rate=1";
1764 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1765 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1766 my $controller = int($drive->{index} / $maxdev);
1767 my $unit = $drive->{index} % $maxdev;
1768 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1770 $device = "ide-$devicetype";
1771 if ($drive->{interface
} eq 'ide') {
1772 $device .= ",bus=ide.$controller,unit=$unit";
1774 $device .= ",bus=ahci$controller.$unit";
1776 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1778 if ($devicetype eq 'hd') {
1779 if (my $model = $drive->{model
}) {
1780 $model = URI
::Escape
::uri_unescape
($model);
1781 $device .= ",model=$model";
1783 if ($drive->{ssd
}) {
1784 $device .= ",rotation_rate=1";
1787 } elsif ($drive->{interface
} eq 'usb') {
1789 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1791 die "unsupported interface type";
1794 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1796 if (my $serial = $drive->{serial
}) {
1797 $serial = URI
::Escape
::uri_unescape
($serial);
1798 $device .= ",serial=$serial";
1805 sub get_initiator_name
{
1808 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1809 while (defined(my $line = <$fh>)) {
1810 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1819 sub print_drive_full
{
1820 my ($storecfg, $vmid, $drive) = @_;
1823 my $volid = $drive->{file
};
1826 if (drive_is_cdrom
($drive)) {
1827 $path = get_iso_path
($storecfg, $vmid, $volid);
1829 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1831 $path = PVE
::Storage
::path
($storecfg, $volid);
1832 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1833 $format = qemu_img_format
($scfg, $volname);
1841 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1842 foreach my $o (@qemu_drive_options) {
1843 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1846 # snapshot only accepts on|off
1847 if (defined($drive->{snapshot
})) {
1848 my $v = $drive->{snapshot
} ?
'on' : 'off';
1849 $opts .= ",snapshot=$v";
1852 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1853 my ($dir, $qmpname) = @$type;
1854 if (my $v = $drive->{"mbps$dir"}) {
1855 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1857 if (my $v = $drive->{"mbps${dir}_max"}) {
1858 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1860 if (my $v = $drive->{"bps${dir}_max_length"}) {
1861 $opts .= ",throttling.bps$qmpname-max-length=$v";
1863 if (my $v = $drive->{"iops${dir}"}) {
1864 $opts .= ",throttling.iops$qmpname=$v";
1866 if (my $v = $drive->{"iops${dir}_max"}) {
1867 $opts .= ",throttling.iops$qmpname-max=$v";
1869 if (my $v = $drive->{"iops${dir}_max_length"}) {
1870 $opts .= ",throttling.iops$qmpname-max-length=$v";
1874 $opts .= ",format=$format" if $format && !$drive->{format
};
1876 my $cache_direct = 0;
1878 if (my $cache = $drive->{cache
}) {
1879 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1880 } elsif (!drive_is_cdrom
($drive)) {
1881 $opts .= ",cache=none";
1885 # aio native works only with O_DIRECT
1886 if (!$drive->{aio
}) {
1888 $opts .= ",aio=native";
1890 $opts .= ",aio=threads";
1894 if (!drive_is_cdrom
($drive)) {
1896 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1897 $detectzeroes = 'off';
1898 } elsif ($drive->{discard
}) {
1899 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1901 # This used to be our default with discard not being specified:
1902 $detectzeroes = 'on';
1904 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1907 my $pathinfo = $path ?
"file=$path," : '';
1909 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1912 sub print_netdevice_full
{
1913 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1915 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1917 my $device = $net->{model
};
1918 if ($net->{model
} eq 'virtio') {
1919 $device = 'virtio-net-pci';
1922 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1923 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1924 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1925 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1926 my $vectors = $net->{queues
} * 2 + 2;
1927 $tmpstr .= ",vectors=$vectors,mq=on";
1929 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1931 if ($use_old_bios_files) {
1933 if ($device eq 'virtio-net-pci') {
1934 $romfile = 'pxe-virtio.rom';
1935 } elsif ($device eq 'e1000') {
1936 $romfile = 'pxe-e1000.rom';
1937 } elsif ($device eq 'ne2k') {
1938 $romfile = 'pxe-ne2k_pci.rom';
1939 } elsif ($device eq 'pcnet') {
1940 $romfile = 'pxe-pcnet.rom';
1941 } elsif ($device eq 'rtl8139') {
1942 $romfile = 'pxe-rtl8139.rom';
1944 $tmpstr .= ",romfile=$romfile" if $romfile;
1950 sub print_netdev_full
{
1951 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1954 if ($netid =~ m/^net(\d+)$/) {
1958 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1960 my $ifname = "tap${vmid}i$i";
1962 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1963 die "interface name '$ifname' is too long (max 15 character)\n"
1964 if length($ifname) >= 16;
1966 my $vhostparam = '';
1967 if (is_native
($arch)) {
1968 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1971 my $vmname = $conf->{name
} || "vm$vmid";
1974 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1976 if ($net->{bridge
}) {
1977 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1979 $netdev = "type=user,id=$netid,hostname=$vmname";
1982 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1988 sub print_cpu_device
{
1989 my ($conf, $id) = @_;
1991 my $kvm = $conf->{kvm
} // 1;
1992 my $cpu = $kvm ?
"kvm64" : "qemu64";
1993 if (my $cputype = $conf->{cpu
}) {
1994 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1995 or die "Cannot parse cpu description: $cputype\n";
1996 $cpu = $cpuconf->{cputype
};
1999 my $cores = $conf->{cores
} || 1;
2001 my $current_core = ($id - 1) % $cores;
2002 my $current_socket = int(($id - 1 - $current_core)/$cores);
2004 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2008 'cirrus' => 'cirrus-vga',
2010 'vmware' => 'vmware-svga',
2011 'virtio' => 'virtio-vga',
2014 sub print_vga_device
{
2015 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2017 my $type = $vga_map->{$vga->{type
}};
2018 if ($type eq 'virtio-vga' && $arch eq 'aarch64') {
2019 $type = 'virtio-gpu';
2021 my $vgamem_mb = $vga->{memory
};
2023 $type = $id ?
'qxl' : 'qxl-vga';
2025 die "no devicetype for $vga->{type}\n" if !$type;
2029 if ($vga->{type
} eq 'virtio') {
2030 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2031 $memory = ",max_hostmem=$bytes";
2033 # from https://www.spice-space.org/multiple-monitors.html
2034 $memory = ",vgamem_mb=$vga->{memory}";
2035 my $ram = $vgamem_mb * 4;
2036 my $vram = $vgamem_mb * 2;
2037 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2039 $memory = ",vgamem_mb=$vga->{memory}";
2041 } elsif ($qxlnum && $id) {
2042 $memory = ",ram_size=67108864,vram_size=33554432";
2045 my $q35 = machine_type_is_q35
($conf);
2046 my $vgaid = "vga" . ($id // '');
2049 if ($q35 && $vgaid eq 'vga') {
2050 # the first display uses pcie.0 bus on q35 machines
2051 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2053 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2056 return "$type,id=${vgaid}${memory}${pciaddr}";
2059 sub drive_is_cloudinit
{
2061 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2064 sub drive_is_cdrom
{
2065 my ($drive, $exclude_cloudinit) = @_;
2067 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2069 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2073 sub parse_number_sets
{
2076 foreach my $part (split(/;/, $set)) {
2077 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2078 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2079 push @$res, [ $1, $2 ];
2081 die "invalid range: $part\n";
2090 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2091 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2092 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2099 return undef if !$value;
2101 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2103 my @idlist = split(/;/, $res->{host
});
2104 delete $res->{host
};
2105 foreach my $id (@idlist) {
2106 if ($id =~ /^$PCIRE$/) {
2108 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
2110 my $pcidevices = PVE
::SysFSTools
::lspci
($1);
2111 $res->{pciid
} = $pcidevices->{$1};
2114 # should have been caught by parse_property_string already
2115 die "failed to parse PCI id: $id\n";
2121 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2125 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2130 if (!defined($res->{macaddr
})) {
2131 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2132 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2137 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2138 sub parse_ipconfig
{
2141 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2147 if ($res->{gw
} && !$res->{ip
}) {
2148 warn 'gateway specified without specifying an IP address';
2151 if ($res->{gw6
} && !$res->{ip6
}) {
2152 warn 'IPv6 gateway specified without specifying an IPv6 address';
2155 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2156 warn 'gateway specified together with DHCP';
2159 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2161 warn "IPv6 gateway specified together with $res->{ip6} address";
2165 if (!$res->{ip
} && !$res->{ip6
}) {
2166 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2175 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2178 sub add_random_macs
{
2179 my ($settings) = @_;
2181 foreach my $opt (keys %$settings) {
2182 next if $opt !~ m/^net(\d+)$/;
2183 my $net = parse_net
($settings->{$opt});
2185 $settings->{$opt} = print_net
($net);
2189 sub vm_is_volid_owner
{
2190 my ($storecfg, $vmid, $volid) = @_;
2192 if ($volid !~ m
|^/|) {
2194 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2195 if ($owner && ($owner == $vmid)) {
2203 sub split_flagged_list
{
2204 my $text = shift || '';
2205 $text =~ s/[,;]/ /g;
2207 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2210 sub join_flagged_list
{
2211 my ($how, $lst) = @_;
2212 join $how, map { $lst->{$_} . $_ } keys %$lst;
2215 sub vmconfig_delete_pending_option
{
2216 my ($conf, $key, $force) = @_;
2218 delete $conf->{pending
}->{$key};
2219 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2220 $pending_delete_hash->{$key} = $force ?
'!' : '';
2221 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2224 sub vmconfig_undelete_pending_option
{
2225 my ($conf, $key) = @_;
2227 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2228 delete $pending_delete_hash->{$key};
2230 if (%$pending_delete_hash) {
2231 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2233 delete $conf->{pending
}->{delete};
2237 sub vmconfig_register_unused_drive
{
2238 my ($storecfg, $vmid, $conf, $drive) = @_;
2240 if (drive_is_cloudinit
($drive)) {
2241 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2243 } elsif (!drive_is_cdrom
($drive)) {
2244 my $volid = $drive->{file
};
2245 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2246 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2251 sub vmconfig_cleanup_pending
{
2254 # remove pending changes when nothing changed
2256 foreach my $opt (keys %{$conf->{pending
}}) {
2257 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2259 delete $conf->{pending
}->{$opt};
2263 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2264 my $pending_delete_hash = {};
2265 while (my ($opt, $force) = each %$current_delete_hash) {
2266 if (defined($conf->{$opt})) {
2267 $pending_delete_hash->{$opt} = $force;
2273 if (%$pending_delete_hash) {
2274 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2276 delete $conf->{pending
}->{delete};
2282 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2286 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2287 format_description
=> 'UUID',
2288 description
=> "Set SMBIOS1 UUID.",
2294 format_description
=> 'string',
2295 description
=> "Set SMBIOS1 version.",
2301 format_description
=> 'string',
2302 description
=> "Set SMBIOS1 serial number.",
2308 format_description
=> 'string',
2309 description
=> "Set SMBIOS1 manufacturer.",
2315 format_description
=> 'string',
2316 description
=> "Set SMBIOS1 product ID.",
2322 format_description
=> 'string',
2323 description
=> "Set SMBIOS1 SKU string.",
2329 format_description
=> 'string',
2330 description
=> "Set SMBIOS1 family string.",
2338 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2345 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2348 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2350 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2351 sub verify_bootdisk
{
2352 my ($value, $noerr) = @_;
2354 return $value if is_valid_drivename
($value);
2356 return undef if $noerr;
2358 die "invalid boot disk '$value'\n";
2361 sub parse_watchdog
{
2364 return undef if !$value;
2366 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2371 sub parse_guest_agent
{
2374 return {} if !defined($value->{agent
});
2376 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2379 # if the agent is disabled ignore the other potentially set properties
2380 return {} if !$res->{enabled
};
2387 return {} if !$value;
2388 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2393 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2394 sub verify_usb_device
{
2395 my ($value, $noerr) = @_;
2397 return $value if parse_usb_device
($value);
2399 return undef if $noerr;
2401 die "unable to parse usb device\n";
2404 # add JSON properties for create and set function
2405 sub json_config_properties
{
2408 foreach my $opt (keys %$confdesc) {
2409 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2410 $prop->{$opt} = $confdesc->{$opt};
2416 # return copy of $confdesc_cloudinit to generate documentation
2417 sub cloudinit_config_properties
{
2419 return dclone
($confdesc_cloudinit);
2423 my ($key, $value) = @_;
2425 die "unknown setting '$key'\n" if !$confdesc->{$key};
2427 my $type = $confdesc->{$key}->{type
};
2429 if (!defined($value)) {
2430 die "got undefined value\n";
2433 if ($value =~ m/[\n\r]/) {
2434 die "property contains a line feed\n";
2437 if ($type eq 'boolean') {
2438 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2439 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2440 die "type check ('boolean') failed - got '$value'\n";
2441 } elsif ($type eq 'integer') {
2442 return int($1) if $value =~ m/^(\d+)$/;
2443 die "type check ('integer') failed - got '$value'\n";
2444 } elsif ($type eq 'number') {
2445 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2446 die "type check ('number') failed - got '$value'\n";
2447 } elsif ($type eq 'string') {
2448 if (my $fmt = $confdesc->{$key}->{format
}) {
2449 PVE
::JSONSchema
::check_format
($fmt, $value);
2452 $value =~ s/^\"(.*)\"$/$1/;
2455 die "internal error"
2462 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2463 utime undef, undef, $conf;
2467 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2469 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2471 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2473 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2475 if ($conf->{template
}) {
2476 # check if any base image is still used by a linked clone
2477 foreach_drive
($conf, sub {
2478 my ($ds, $drive) = @_;
2480 return if drive_is_cdrom
($drive);
2482 my $volid = $drive->{file
};
2484 return if !$volid || $volid =~ m
|^/|;
2486 die "base volume '$volid' is still in use by linked cloned\n"
2487 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2492 # only remove disks owned by this VM
2493 foreach_drive
($conf, sub {
2494 my ($ds, $drive) = @_;
2496 return if drive_is_cdrom
($drive, 1);
2498 my $volid = $drive->{file
};
2500 return if !$volid || $volid =~ m
|^/|;
2502 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2503 return if !$path || !$owner || ($owner != $vmid);
2506 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2508 warn "Could not remove disk '$volid', check manually: $@" if $@;
2512 if ($keep_empty_config) {
2513 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2518 # also remove unused disk
2520 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2523 PVE
::Storage
::foreach_volid
($dl, sub {
2524 my ($volid, $sid, $volname, $d) = @_;
2525 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2534 sub parse_vm_config
{
2535 my ($filename, $raw) = @_;
2537 return undef if !defined($raw);
2540 digest
=> Digest
::SHA
::sha1_hex
($raw),
2545 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2546 || die "got strange filename '$filename'";
2554 my @lines = split(/\n/, $raw);
2555 foreach my $line (@lines) {
2556 next if $line =~ m/^\s*$/;
2558 if ($line =~ m/^\[PENDING\]\s*$/i) {
2559 $section = 'pending';
2560 if (defined($descr)) {
2562 $conf->{description
} = $descr;
2565 $conf = $res->{$section} = {};
2568 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2570 if (defined($descr)) {
2572 $conf->{description
} = $descr;
2575 $conf = $res->{snapshots
}->{$section} = {};
2579 if ($line =~ m/^\#(.*)\s*$/) {
2580 $descr = '' if !defined($descr);
2581 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2585 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2586 $descr = '' if !defined($descr);
2587 $descr .= PVE
::Tools
::decode_text
($2);
2588 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2589 $conf->{snapstate
} = $1;
2590 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2593 $conf->{$key} = $value;
2594 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2596 if ($section eq 'pending') {
2597 $conf->{delete} = $value; # we parse this later
2599 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2601 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2604 eval { $value = check_type
($key, $value); };
2606 warn "vm $vmid - unable to parse value of '$key' - $@";
2608 $key = 'ide2' if $key eq 'cdrom';
2609 my $fmt = $confdesc->{$key}->{format
};
2610 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2611 my $v = parse_drive
($key, $value);
2612 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2613 $v->{file
} = $volid;
2614 $value = print_drive
($vmid, $v);
2616 warn "vm $vmid - unable to parse value of '$key'\n";
2621 $conf->{$key} = $value;
2626 if (defined($descr)) {
2628 $conf->{description
} = $descr;
2630 delete $res->{snapstate
}; # just to be sure
2635 sub write_vm_config
{
2636 my ($filename, $conf) = @_;
2638 delete $conf->{snapstate
}; # just to be sure
2640 if ($conf->{cdrom
}) {
2641 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2642 $conf->{ide2
} = $conf->{cdrom
};
2643 delete $conf->{cdrom
};
2646 # we do not use 'smp' any longer
2647 if ($conf->{sockets
}) {
2648 delete $conf->{smp
};
2649 } elsif ($conf->{smp
}) {
2650 $conf->{sockets
} = $conf->{smp
};
2651 delete $conf->{cores
};
2652 delete $conf->{smp
};
2655 my $used_volids = {};
2657 my $cleanup_config = sub {
2658 my ($cref, $pending, $snapname) = @_;
2660 foreach my $key (keys %$cref) {
2661 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2662 $key eq 'snapstate' || $key eq 'pending';
2663 my $value = $cref->{$key};
2664 if ($key eq 'delete') {
2665 die "propertry 'delete' is only allowed in [PENDING]\n"
2667 # fixme: check syntax?
2670 eval { $value = check_type
($key, $value); };
2671 die "unable to parse value of '$key' - $@" if $@;
2673 $cref->{$key} = $value;
2675 if (!$snapname && is_valid_drivename
($key)) {
2676 my $drive = parse_drive
($key, $value);
2677 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2682 &$cleanup_config($conf);
2684 &$cleanup_config($conf->{pending
}, 1);
2686 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2687 die "internal error" if $snapname eq 'pending';
2688 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2691 # remove 'unusedX' settings if we re-add a volume
2692 foreach my $key (keys %$conf) {
2693 my $value = $conf->{$key};
2694 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2695 delete $conf->{$key};
2699 my $generate_raw_config = sub {
2700 my ($conf, $pending) = @_;
2704 # add description as comment to top of file
2705 if (defined(my $descr = $conf->{description
})) {
2707 foreach my $cl (split(/\n/, $descr)) {
2708 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2711 $raw .= "#\n" if $pending;
2715 foreach my $key (sort keys %$conf) {
2716 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2717 $raw .= "$key: $conf->{$key}\n";
2722 my $raw = &$generate_raw_config($conf);
2724 if (scalar(keys %{$conf->{pending
}})){
2725 $raw .= "\n[PENDING]\n";
2726 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2729 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2730 $raw .= "\n[$snapname]\n";
2731 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2741 # we use static defaults from our JSON schema configuration
2742 foreach my $key (keys %$confdesc) {
2743 if (defined(my $default = $confdesc->{$key}->{default})) {
2744 $res->{$key} = $default;
2752 my $vmlist = PVE
::Cluster
::get_vmlist
();
2754 return $res if !$vmlist || !$vmlist->{ids
};
2755 my $ids = $vmlist->{ids
};
2757 foreach my $vmid (keys %$ids) {
2758 my $d = $ids->{$vmid};
2759 next if !$d->{node
} || $d->{node
} ne $nodename;
2760 next if !$d->{type
} || $d->{type
} ne 'qemu';
2761 $res->{$vmid}->{exists} = 1;
2766 # test if VM uses local resources (to prevent migration)
2767 sub check_local_resources
{
2768 my ($conf, $noerr) = @_;
2772 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2773 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2775 foreach my $k (keys %$conf) {
2776 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2777 # sockets are safe: they will recreated be on the target side post-migrate
2778 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2779 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2782 die "VM uses local resources\n" if $loc_res && !$noerr;
2787 # check if used storages are available on all nodes (use by migrate)
2788 sub check_storage_availability
{
2789 my ($storecfg, $conf, $node) = @_;
2791 foreach_drive
($conf, sub {
2792 my ($ds, $drive) = @_;
2794 my $volid = $drive->{file
};
2797 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2800 # check if storage is available on both nodes
2801 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2802 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2806 # list nodes where all VM images are available (used by has_feature API)
2808 my ($conf, $storecfg) = @_;
2810 my $nodelist = PVE
::Cluster
::get_nodelist
();
2811 my $nodehash = { map { $_ => 1 } @$nodelist };
2812 my $nodename = PVE
::INotify
::nodename
();
2814 foreach_drive
($conf, sub {
2815 my ($ds, $drive) = @_;
2817 my $volid = $drive->{file
};
2820 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2822 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2823 if ($scfg->{disable
}) {
2825 } elsif (my $avail = $scfg->{nodes
}) {
2826 foreach my $node (keys %$nodehash) {
2827 delete $nodehash->{$node} if !$avail->{$node};
2829 } elsif (!$scfg->{shared
}) {
2830 foreach my $node (keys %$nodehash) {
2831 delete $nodehash->{$node} if $node ne $nodename
2841 my ($pidfile, $pid) = @_;
2843 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2847 return undef if !$line;
2848 my @param = split(/\0/, $line);
2850 my $cmd = $param[0];
2851 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2853 for (my $i = 0; $i < scalar (@param); $i++) {
2856 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2857 my $p = $param[$i+1];
2858 return 1 if $p && ($p eq $pidfile);
2867 my ($vmid, $nocheck, $node) = @_;
2869 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2871 die "unable to find configuration file for VM $vmid - no such machine\n"
2872 if !$nocheck && ! -f
$filename;
2874 my $pidfile = pidfile_name
($vmid);
2876 if (my $fd = IO
::File-
>new("<$pidfile")) {
2881 my $mtime = $st->mtime;
2882 if ($mtime > time()) {
2883 warn "file '$filename' modified in future\n";
2886 if ($line =~ m/^(\d+)$/) {
2888 if (check_cmdline
($pidfile, $pid)) {
2889 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2901 my $vzlist = config_list
();
2903 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2905 while (defined(my $de = $fd->read)) {
2906 next if $de !~ m/^(\d+)\.pid$/;
2908 next if !defined($vzlist->{$vmid});
2909 if (my $pid = check_running
($vmid)) {
2910 $vzlist->{$vmid}->{pid
} = $pid;
2918 my ($storecfg, $conf) = @_;
2920 my $bootdisk = $conf->{bootdisk
};
2921 return undef if !$bootdisk;
2922 return undef if !is_valid_drivename
($bootdisk);
2924 return undef if !$conf->{$bootdisk};
2926 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2927 return undef if !defined($drive);
2929 return undef if drive_is_cdrom
($drive);
2931 my $volid = $drive->{file
};
2932 return undef if !$volid;
2934 return $drive->{size
};
2937 our $vmstatus_return_properties = {
2938 vmid
=> get_standard_option
('pve-vmid'),
2940 description
=> "Qemu process status.",
2942 enum
=> ['stopped', 'running'],
2945 description
=> "Maximum memory in bytes.",
2948 renderer
=> 'bytes',
2951 description
=> "Root disk size in bytes.",
2954 renderer
=> 'bytes',
2957 description
=> "VM name.",
2962 description
=> "Qemu QMP agent status.",
2967 description
=> "PID of running qemu process.",
2972 description
=> "Uptime.",
2975 renderer
=> 'duration',
2978 description
=> "Maximum usable CPUs.",
2984 my $last_proc_pid_stat;
2986 # get VM status information
2987 # This must be fast and should not block ($full == false)
2988 # We only query KVM using QMP if $full == true (this can be slow)
2990 my ($opt_vmid, $full) = @_;
2994 my $storecfg = PVE
::Storage
::config
();
2996 my $list = vzlist
();
2997 my $defaults = load_defaults
();
2999 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3001 my $cpucount = $cpuinfo->{cpus
} || 1;
3003 foreach my $vmid (keys %$list) {
3004 next if $opt_vmid && ($vmid ne $opt_vmid);
3006 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3007 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3009 my $d = { vmid
=> $vmid };
3010 $d->{pid
} = $list->{$vmid}->{pid
};
3012 # fixme: better status?
3013 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3015 my $size = disksize
($storecfg, $conf);
3016 if (defined($size)) {
3017 $d->{disk
} = 0; # no info available
3018 $d->{maxdisk
} = $size;
3024 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3025 * ($conf->{cores
} || $defaults->{cores
});
3026 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3027 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3029 $d->{name
} = $conf->{name
} || "VM $vmid";
3030 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3031 : $defaults->{memory
}*(1024*1024);
3033 if ($conf->{balloon
}) {
3034 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3035 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3036 : $defaults->{shares
};
3047 $d->{diskwrite
} = 0;
3049 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3051 $d->{serial
} = 1 if conf_has_serial
($conf);
3056 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3057 foreach my $dev (keys %$netdev) {
3058 next if $dev !~ m/^tap([1-9]\d*)i/;
3060 my $d = $res->{$vmid};
3063 $d->{netout
} += $netdev->{$dev}->{receive
};
3064 $d->{netin
} += $netdev->{$dev}->{transmit
};
3067 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3068 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3073 my $ctime = gettimeofday
;
3075 foreach my $vmid (keys %$list) {
3077 my $d = $res->{$vmid};
3078 my $pid = $d->{pid
};
3081 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3082 next if !$pstat; # not running
3084 my $used = $pstat->{utime} + $pstat->{stime
};
3086 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3088 if ($pstat->{vsize
}) {
3089 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3092 my $old = $last_proc_pid_stat->{$pid};
3094 $last_proc_pid_stat->{$pid} = {
3102 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3104 if ($dtime > 1000) {
3105 my $dutime = $used - $old->{used
};
3107 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3108 $last_proc_pid_stat->{$pid} = {
3114 $d->{cpu
} = $old->{cpu
};
3118 return $res if !$full;
3120 my $qmpclient = PVE
::QMPClient-
>new();
3122 my $ballooncb = sub {
3123 my ($vmid, $resp) = @_;
3125 my $info = $resp->{'return'};
3126 return if !$info->{max_mem
};
3128 my $d = $res->{$vmid};
3130 # use memory assigned to VM
3131 $d->{maxmem
} = $info->{max_mem
};
3132 $d->{balloon
} = $info->{actual
};
3134 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3135 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3136 $d->{freemem
} = $info->{free_mem
};
3139 $d->{ballooninfo
} = $info;
3142 my $blockstatscb = sub {
3143 my ($vmid, $resp) = @_;
3144 my $data = $resp->{'return'} || [];
3145 my $totalrdbytes = 0;
3146 my $totalwrbytes = 0;
3148 for my $blockstat (@$data) {
3149 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3150 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3152 $blockstat->{device
} =~ s/drive-//;
3153 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3155 $res->{$vmid}->{diskread
} = $totalrdbytes;
3156 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3159 my $statuscb = sub {
3160 my ($vmid, $resp) = @_;
3162 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3163 # this fails if ballon driver is not loaded, so this must be
3164 # the last commnand (following command are aborted if this fails).
3165 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3167 my $status = 'unknown';
3168 if (!defined($status = $resp->{'return'}->{status
})) {
3169 warn "unable to get VM status\n";
3173 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3176 foreach my $vmid (keys %$list) {
3177 next if $opt_vmid && ($vmid ne $opt_vmid);
3178 next if !$res->{$vmid}->{pid
}; # not running
3179 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3182 $qmpclient->queue_execute(undef, 2);
3184 foreach my $vmid (keys %$list) {
3185 next if $opt_vmid && ($vmid ne $opt_vmid);
3186 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3193 my ($conf, $func, @param) = @_;
3195 foreach my $ds (valid_drive_names
()) {
3196 next if !defined($conf->{$ds});
3198 my $drive = parse_drive
($ds, $conf->{$ds});
3201 &$func($ds, $drive, @param);
3206 my ($conf, $func, @param) = @_;
3210 my $test_volid = sub {
3211 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3215 $volhash->{$volid}->{cdrom
} //= 1;
3216 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3218 $volhash->{$volid}->{replicate
} //= 0;
3219 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3221 $volhash->{$volid}->{shared
} //= 0;
3222 $volhash->{$volid}->{shared
} = 1 if $shared;
3224 $volhash->{$volid}->{referenced_in_config
} //= 0;
3225 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3227 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3228 if defined($snapname);
3231 foreach_drive
($conf, sub {
3232 my ($ds, $drive) = @_;
3233 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3236 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3237 my $snap = $conf->{snapshots
}->{$snapname};
3238 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3239 foreach_drive
($snap, sub {
3240 my ($ds, $drive) = @_;
3241 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3245 foreach my $volid (keys %$volhash) {
3246 &$func($volid, $volhash->{$volid}, @param);
3250 sub conf_has_serial
{
3253 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3254 if ($conf->{"serial$i"}) {
3262 sub vga_conf_has_spice
{
3265 my $vgaconf = parse_vga
($vga);
3266 my $vgatype = $vgaconf->{type
};
3267 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3272 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3273 sub get_host_arch
() {
3274 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3280 return get_host_arch
() eq $arch;
3283 my $default_machines = {
3288 sub get_basic_machine_info
{
3289 my ($conf, $forcemachine) = @_;
3291 my $arch = $conf->{arch
} // get_host_arch
();
3292 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3293 return ($arch, $machine);
3296 sub get_ovmf_files
($) {
3299 my $ovmf = $OVMF->{$arch}
3300 or die "no OVMF images known for architecture '$arch'\n";
3306 aarch64
=> '/usr/bin/qemu-system-aarch64',
3307 x86_64
=> '/usr/bin/qemu-system-x86_64',
3309 sub get_command_for_arch
($) {
3311 return '/usr/bin/kvm' if is_native
($arch);
3313 my $cmd = $Arch2Qemu->{$arch}
3314 or die "don't know how to emulate architecture '$arch'\n";
3318 sub get_cpu_options
{
3319 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3322 my $ostype = $conf->{ostype
};
3324 my $cpu = $kvm ?
"kvm64" : "qemu64";
3325 if ($arch eq 'aarch64') {
3326 $cpu = 'cortex-a57';
3328 if (my $cputype = $conf->{cpu
}) {
3329 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3330 or die "Cannot parse cpu description: $cputype\n";
3331 $cpu = $cpuconf->{cputype
};
3332 $kvm_off = 1 if $cpuconf->{hidden
};
3334 if (defined(my $flags = $cpuconf->{flags
})) {
3335 push @$cpuFlags, split(";", $flags);
3339 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3341 push @$cpuFlags , '-x2apic'
3342 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3344 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3346 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3348 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3350 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3351 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3354 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3356 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3358 push @$cpuFlags, 'kvm=off' if $kvm_off;
3360 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3361 push @$cpuFlags, "vendor=${cpu_vendor}"
3362 if $cpu_vendor ne 'default';
3363 } elsif ($arch ne 'aarch64') {
3364 die "internal error"; # should not happen
3367 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3369 return ('-cpu', $cpu);
3372 sub config_to_command
{
3373 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3376 my $globalFlags = [];
3377 my $machineFlags = [];
3382 my $kvmver = kvm_user_version
();
3383 my $vernum = 0; # unknown
3384 my $ostype = $conf->{ostype
};
3385 my $winversion = windows_version
($ostype);
3386 my $kvm = $conf->{kvm
};
3388 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3389 $kvm //= 1 if is_native
($arch);
3392 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3393 if !defined kvm_version
();
3396 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3397 $vernum = $1*1000000+$2*1000;
3398 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3399 $vernum = $1*1000000+$2*1000+$3;
3402 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3404 my $have_ovz = -f
'/proc/vz/vestat';
3406 my $q35 = machine_type_is_q35
($conf);
3407 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3408 my $use_old_bios_files = undef;
3409 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3411 my $cpuunits = defined($conf->{cpuunits
}) ?
3412 $conf->{cpuunits
} : $defaults->{cpuunits
};
3414 push @$cmd, get_command_for_arch
($arch);
3416 push @$cmd, '-id', $vmid;
3418 my $vmname = $conf->{name
} || "vm$vmid";
3420 push @$cmd, '-name', $vmname;
3424 my $qmpsocket = qmp_socket
($vmid);
3425 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3426 push @$cmd, '-mon', "chardev=qmp,mode=control";
3428 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3429 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3430 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3433 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3435 push @$cmd, '-daemonize';
3437 if ($conf->{smbios1
}) {
3438 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3441 if ($conf->{vmgenid
}) {
3442 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3445 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3446 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3447 die "uefi base image not found\n" if ! -f
$ovmf_code;
3451 if (my $efidisk = $conf->{efidisk0
}) {
3452 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3453 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3454 $format = $d->{format
};
3456 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3457 if (!defined($format)) {
3458 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3459 $format = qemu_img_format
($scfg, $volname);
3463 die "efidisk format must be specified\n"
3464 if !defined($format);
3467 warn "no efidisk configured! Using temporary efivars disk.\n";
3468 $path = "/tmp/$vmid-ovmf.fd";
3469 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3473 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3474 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3478 # add usb controllers
3479 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3480 push @$devices, @usbcontrollers if @usbcontrollers;
3481 my $vga = parse_vga
($conf->{vga
});
3483 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3484 $vga->{type
} = 'qxl' if $qxlnum;
3486 if (!$vga->{type
}) {
3487 if ($arch eq 'aarch64') {
3488 $vga->{type
} = 'virtio';
3489 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3490 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3492 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3496 # enable absolute mouse coordinates (needed by vnc)
3498 if (defined($conf->{tablet
})) {
3499 $tablet = $conf->{tablet
};
3501 $tablet = $defaults->{tablet
};
3502 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3503 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3507 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3508 my $kbd = print_keyboarddevice_full
($conf, $arch);
3509 push @$devices, '-device', $kbd if defined($kbd);
3513 my $gpu_passthrough;
3516 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3517 my $d = parse_hostpci
($conf->{"hostpci$i"});
3520 my $pcie = $d->{pcie
};
3522 die "q35 machine model is not enabled" if !$q35;
3523 $pciaddr = print_pcie_addr
("hostpci$i");
3525 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3528 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3529 my $romfile = $d->{romfile
};
3532 if ($d->{'x-vga'}) {
3533 $xvga = ',x-vga=on';
3535 $vga->{type
} = 'none';
3536 $gpu_passthrough = 1;
3538 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3542 my $pcidevices = $d->{pciid
};
3543 my $multifunction = 1 if @$pcidevices > 1;
3546 foreach my $pcidevice (@$pcidevices) {
3548 my $id = "hostpci$i";
3549 $id .= ".$j" if $multifunction;
3550 my $addr = $pciaddr;
3551 $addr .= ".$j" if $multifunction;
3552 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3555 $devicestr .= "$rombar$xvga";
3556 $devicestr .= ",multifunction=on" if $multifunction;
3557 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3560 push @$devices, '-device', $devicestr;
3566 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3567 push @$devices, @usbdevices if @usbdevices;
3569 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3570 if (my $path = $conf->{"serial$i"}) {
3571 if ($path eq 'socket') {
3572 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3573 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3574 # On aarch64, serial0 is the UART device. Qemu only allows
3575 # connecting UART devices via the '-serial' command line, as
3576 # the device has a fixed slot on the hardware...
3577 if ($arch eq 'aarch64' && $i == 0) {
3578 push @$devices, '-serial', "chardev:serial$i";
3580 push @$devices, '-device', "isa-serial,chardev=serial$i";
3583 die "no such serial device\n" if ! -c
$path;
3584 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3585 push @$devices, '-device', "isa-serial,chardev=serial$i";
3591 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3592 if (my $path = $conf->{"parallel$i"}) {
3593 die "no such parallel device\n" if ! -c
$path;
3594 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3595 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3596 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3602 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3603 $sockets = $conf->{sockets
} if $conf->{sockets
};
3605 my $cores = $conf->{cores
} || 1;
3607 my $maxcpus = $sockets * $cores;
3609 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3611 my $allowed_vcpus = $cpuinfo->{cpus
};
3613 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3614 if ($allowed_vcpus < $maxcpus);
3616 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3618 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3619 for (my $i = 2; $i <= $vcpus; $i++) {
3620 my $cpustr = print_cpu_device
($conf,$i);
3621 push @$cmd, '-device', $cpustr;
3626 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3628 push @$cmd, '-nodefaults';
3630 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3632 my $bootindex_hash = {};
3634 foreach my $o (split(//, $bootorder)) {
3635 $bootindex_hash->{$o} = $i*100;
3639 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3641 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3643 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3645 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3646 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3647 my $socket = vnc_socket
($vmid);
3648 push @$cmd, '-vnc', "unix:$socket,x509,password";
3650 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3651 push @$cmd, '-nographic';
3655 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3657 my $useLocaltime = $conf->{localtime};
3659 if ($winversion >= 5) { # windows
3660 $useLocaltime = 1 if !defined($conf->{localtime});
3662 # use time drift fix when acpi is enabled
3663 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3664 $tdf = 1 if !defined($conf->{tdf
});
3668 if ($winversion >= 6) {
3669 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3670 push @$cmd, '-no-hpet';
3673 push @$rtcFlags, 'driftfix=slew' if $tdf;
3676 push @$machineFlags, 'accel=tcg';
3679 if ($machine_type) {
3680 push @$machineFlags, "type=${machine_type}";
3683 if ($conf->{startdate
}) {
3684 push @$rtcFlags, "base=$conf->{startdate}";
3685 } elsif ($useLocaltime) {
3686 push @$rtcFlags, 'base=localtime';
3689 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3691 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3693 push @$cmd, '-S' if $conf->{freeze
};
3695 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3698 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3699 #push @$cmd, '-soundhw', 'es1370';
3700 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3702 if (parse_guest_agent
($conf)->{enabled
}) {
3703 my $qgasocket = qmp_socket
($vmid, 1);
3704 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3705 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3706 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3707 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3715 for(my $i = 1; $i < $qxlnum; $i++){
3716 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3719 # assume other OS works like Linux
3720 my ($ram, $vram) = ("134217728", "67108864");
3721 if ($vga->{memory
}) {
3722 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3723 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3725 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3726 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3730 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3732 my $nodename = PVE
::INotify
::nodename
();
3733 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3734 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3735 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3736 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3737 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3739 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3741 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3742 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3743 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3746 # enable balloon by default, unless explicitly disabled
3747 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3748 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3749 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3752 if ($conf->{watchdog
}) {
3753 my $wdopts = parse_watchdog
($conf->{watchdog
});
3754 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3755 my $watchdog = $wdopts->{model
} || 'i6300esb';
3756 push @$devices, '-device', "$watchdog$pciaddr";
3757 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3761 my $scsicontroller = {};
3762 my $ahcicontroller = {};
3763 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3765 # Add iscsi initiator name if available
3766 if (my $initiator = get_initiator_name
()) {
3767 push @$devices, '-iscsi', "initiator-name=$initiator";
3770 foreach_drive
($conf, sub {
3771 my ($ds, $drive) = @_;
3773 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3774 push @$vollist, $drive->{file
};
3777 # ignore efidisk here, already added in bios/fw handling code above
3778 return if $drive->{interface
} eq 'efidisk';
3780 $use_virtio = 1 if $ds =~ m/^virtio/;
3782 if (drive_is_cdrom
($drive)) {
3783 if ($bootindex_hash->{d
}) {
3784 $drive->{bootindex
} = $bootindex_hash->{d
};
3785 $bootindex_hash->{d
} += 1;
3788 if ($bootindex_hash->{c
}) {
3789 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3790 $bootindex_hash->{c
} += 1;
3794 if($drive->{interface
} eq 'virtio'){
3795 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3798 if ($drive->{interface
} eq 'scsi') {
3800 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3802 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3803 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3806 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3807 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3808 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3809 } elsif ($drive->{iothread
}) {
3810 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3814 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3815 $queues = ",num_queues=$drive->{queues}";
3818 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3819 $scsicontroller->{$controller}=1;
3822 if ($drive->{interface
} eq 'sata') {
3823 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3824 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3825 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3826 $ahcicontroller->{$controller}=1;
3829 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3830 push @$devices, '-drive',$drive_cmd;
3831 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3834 for (my $i = 0; $i < $MAX_NETS; $i++) {
3835 next if !$conf->{"net$i"};
3836 my $d = parse_net
($conf->{"net$i"});
3839 $use_virtio = 1 if $d->{model
} eq 'virtio';
3841 if ($bootindex_hash->{n
}) {
3842 $d->{bootindex
} = $bootindex_hash->{n
};
3843 $bootindex_hash->{n
} += 1;
3846 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3847 push @$devices, '-netdev', $netdevfull;
3849 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3850 push @$devices, '-device', $netdevicefull;
3855 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3860 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3862 while (my ($k, $v) = each %$bridges) {
3863 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3864 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3869 if ($conf->{args
}) {
3870 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3874 push @$cmd, @$devices;
3875 push @$cmd, '-rtc', join(',', @$rtcFlags)
3876 if scalar(@$rtcFlags);
3877 push @$cmd, '-machine', join(',', @$machineFlags)
3878 if scalar(@$machineFlags);
3879 push @$cmd, '-global', join(',', @$globalFlags)
3880 if scalar(@$globalFlags);
3882 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3887 return "${var_run_tmpdir}/$vmid.vnc";
3893 my $res = vm_mon_cmd
($vmid, 'query-spice');
3895 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3899 my ($vmid, $qga, $name) = @_;
3900 my $sockettype = $qga ?
'qga' : 'qmp';
3901 my $ext = $name ?
'-'.$name : '';
3902 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3907 return "${var_run_tmpdir}/$vmid.pid";
3910 sub vm_devices_list
{
3913 my $res = vm_mon_cmd
($vmid, 'query-pci');
3914 my $devices_to_check = [];
3916 foreach my $pcibus (@$res) {
3917 push @$devices_to_check, @{$pcibus->{devices
}},
3920 while (@$devices_to_check) {
3922 for my $d (@$devices_to_check) {
3923 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3924 next if !$d->{'pci_bridge'};
3926 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3927 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3929 $devices_to_check = $to_check;
3932 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3933 foreach my $block (@$resblock) {
3934 if($block->{device
} =~ m/^drive-(\S+)/){
3939 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3940 foreach my $mice (@$resmice) {
3941 if ($mice->{name
} eq 'QEMU HID Tablet') {
3942 $devices->{tablet
} = 1;
3947 # for usb devices there is no query-usb
3948 # but we can iterate over the entries in
3949 # qom-list path=/machine/peripheral
3950 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3951 foreach my $per (@$resperipheral) {
3952 if ($per->{name
} =~ m/^usb\d+$/) {
3953 $devices->{$per->{name
}} = 1;
3961 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3963 my $q35 = machine_type_is_q35
($conf);
3965 my $devices_list = vm_devices_list
($vmid);
3966 return 1 if defined($devices_list->{$deviceid});
3968 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
3970 if ($deviceid eq 'tablet') {
3972 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3974 } elsif ($deviceid eq 'keyboard') {
3976 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3978 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3980 die "usb hotplug currently not reliable\n";
3981 # since we can't reliably hot unplug all added usb devices
3982 # and usb passthrough disables live migration
3983 # we disable usb hotplugging for now
3984 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3986 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3988 qemu_iothread_add
($vmid, $deviceid, $device);
3990 qemu_driveadd
($storecfg, $vmid, $device);
3991 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3993 qemu_deviceadd
($vmid, $devicefull);
3994 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3996 eval { qemu_drivedel
($vmid, $deviceid); };
4001 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4004 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4005 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4006 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4008 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4010 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4011 qemu_iothread_add
($vmid, $deviceid, $device);
4012 $devicefull .= ",iothread=iothread-$deviceid";
4015 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4016 $devicefull .= ",num_queues=$device->{queues}";
4019 qemu_deviceadd
($vmid, $devicefull);
4020 qemu_deviceaddverify
($vmid, $deviceid);
4022 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4024 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4025 qemu_driveadd
($storecfg, $vmid, $device);
4027 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4028 eval { qemu_deviceadd
($vmid, $devicefull); };
4030 eval { qemu_drivedel
($vmid, $deviceid); };
4035 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4037 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4039 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4040 my $use_old_bios_files = undef;
4041 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4043 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4044 qemu_deviceadd
($vmid, $netdevicefull);
4045 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4047 eval { qemu_netdevdel
($vmid, $deviceid); };
4052 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4055 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4056 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4058 qemu_deviceadd
($vmid, $devicefull);
4059 qemu_deviceaddverify
($vmid, $deviceid);
4062 die "can't hotplug device '$deviceid'\n";
4068 # fixme: this should raise exceptions on error!
4069 sub vm_deviceunplug
{
4070 my ($vmid, $conf, $deviceid) = @_;
4072 my $devices_list = vm_devices_list
($vmid);
4073 return 1 if !defined($devices_list->{$deviceid});
4075 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4077 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4079 qemu_devicedel
($vmid, $deviceid);
4081 } elsif ($deviceid =~ m/^usb\d+$/) {
4083 die "usb hotplug currently not reliable\n";
4084 # when unplugging usb devices this way,
4085 # there may be remaining usb controllers/hubs
4086 # so we disable it for now
4087 qemu_devicedel
($vmid, $deviceid);
4088 qemu_devicedelverify
($vmid, $deviceid);
4090 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4092 qemu_devicedel
($vmid, $deviceid);
4093 qemu_devicedelverify
($vmid, $deviceid);
4094 qemu_drivedel
($vmid, $deviceid);
4095 qemu_iothread_del
($conf, $vmid, $deviceid);
4097 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4099 qemu_devicedel
($vmid, $deviceid);
4100 qemu_devicedelverify
($vmid, $deviceid);
4101 qemu_iothread_del
($conf, $vmid, $deviceid);
4103 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4105 qemu_devicedel
($vmid, $deviceid);
4106 qemu_drivedel
($vmid, $deviceid);
4107 qemu_deletescsihw
($conf, $vmid, $deviceid);
4109 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4111 qemu_devicedel
($vmid, $deviceid);
4112 qemu_devicedelverify
($vmid, $deviceid);
4113 qemu_netdevdel
($vmid, $deviceid);
4116 die "can't unplug device '$deviceid'\n";
4122 sub qemu_deviceadd
{
4123 my ($vmid, $devicefull) = @_;
4125 $devicefull = "driver=".$devicefull;
4126 my %options = split(/[=,]/, $devicefull);
4128 vm_mon_cmd
($vmid, "device_add" , %options);
4131 sub qemu_devicedel
{
4132 my ($vmid, $deviceid) = @_;
4134 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4137 sub qemu_iothread_add
{
4138 my($vmid, $deviceid, $device) = @_;
4140 if ($device->{iothread
}) {
4141 my $iothreads = vm_iothreads_list
($vmid);
4142 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4146 sub qemu_iothread_del
{
4147 my($conf, $vmid, $deviceid) = @_;
4149 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4150 if ($device->{iothread
}) {
4151 my $iothreads = vm_iothreads_list
($vmid);
4152 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4156 sub qemu_objectadd
{
4157 my($vmid, $objectid, $qomtype) = @_;
4159 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4164 sub qemu_objectdel
{
4165 my($vmid, $objectid) = @_;
4167 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4173 my ($storecfg, $vmid, $device) = @_;
4175 my $drive = print_drive_full
($storecfg, $vmid, $device);
4176 $drive =~ s/\\/\\\\/g;
4177 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4179 # If the command succeeds qemu prints: "OK
"
4180 return 1 if $ret =~ m/OK/s;
4182 die "adding drive failed
: $ret\n";
4186 my($vmid, $deviceid) = @_;
4188 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4191 return 1 if $ret eq "";
4193 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4194 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4196 die "deleting drive
$deviceid failed
: $ret\n";
4199 sub qemu_deviceaddverify {
4200 my ($vmid, $deviceid) = @_;
4202 for (my $i = 0; $i <= 5; $i++) {
4203 my $devices_list = vm_devices_list($vmid);
4204 return 1 if defined($devices_list->{$deviceid});
4208 die "error on hotplug device
'$deviceid'\n";
4212 sub qemu_devicedelverify {
4213 my ($vmid, $deviceid) = @_;
4215 # need to verify that the device is correctly removed as device_del
4216 # is async and empty return is not reliable
4218 for (my $i = 0; $i <= 5; $i++) {
4219 my $devices_list = vm_devices_list($vmid);
4220 return 1 if !defined($devices_list->{$deviceid});
4224 die "error on hot-unplugging device
'$deviceid'\n";
4227 sub qemu_findorcreatescsihw {
4228 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4230 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4232 my $scsihwid="$controller_prefix$controller";
4233 my $devices_list = vm_devices_list($vmid);
4235 if(!defined($devices_list->{$scsihwid})) {
4236 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4242 sub qemu_deletescsihw {
4243 my ($conf, $vmid, $opt) = @_;
4245 my $device = parse_drive($opt, $conf->{$opt});
4247 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4248 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4252 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4254 my $devices_list = vm_devices_list($vmid);
4255 foreach my $opt (keys %{$devices_list}) {
4256 if (PVE::QemuServer::is_valid_drivename($opt)) {
4257 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4258 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4264 my $scsihwid="scsihw
$controller";
4266 vm_deviceunplug($vmid, $conf, $scsihwid);
4271 sub qemu_add_pci_bridge {
4272 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4278 print_pci_addr($device, $bridges, $arch, $machine_type);
4280 while (my ($k, $v) = each %$bridges) {
4283 return 1 if !defined($bridgeid) || $bridgeid < 1;
4285 my $bridge = "pci
.$bridgeid";
4286 my $devices_list = vm_devices_list($vmid);
4288 if (!defined($devices_list->{$bridge})) {
4289 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4295 sub qemu_set_link_status {
4296 my ($vmid, $device, $up) = @_;
4298 vm_mon_cmd($vmid, "set_link
", name => $device,
4299 up => $up ? JSON::true : JSON::false);
4302 sub qemu_netdevadd {
4303 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4305 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4306 my %options = split(/[=,]/, $netdev);
4308 vm_mon_cmd($vmid, "netdev_add
", %options);
4312 sub qemu_netdevdel {
4313 my ($vmid, $deviceid) = @_;
4315 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4318 sub qemu_usb_hotplug {
4319 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4323 # remove the old one first
4324 vm_deviceunplug($vmid, $conf, $deviceid);
4326 # check if xhci controller is necessary and available
4327 if ($device->{usb3}) {
4329 my $devicelist = vm_devices_list($vmid);
4331 if (!$devicelist->{xhci}) {
4332 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4333 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4336 my $d = parse_usb_device($device->{host});
4337 $d->{usb3} = $device->{usb3};
4340 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4343 sub qemu_cpu_hotplug {
4344 my ($vmid, $conf, $vcpus) = @_;
4346 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4349 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4350 $sockets = $conf->{sockets} if $conf->{sockets};
4351 my $cores = $conf->{cores} || 1;
4352 my $maxcpus = $sockets * $cores;
4354 $vcpus = $maxcpus if !$vcpus;
4356 die "you can
't add more vcpus than maxcpus\n"
4357 if $vcpus > $maxcpus;
4359 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4361 if ($vcpus < $currentvcpus) {
4363 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4365 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4366 qemu_devicedel($vmid, "cpu$i");
4368 my $currentrunningvcpus = undef;
4370 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4371 last if scalar(@{$currentrunningvcpus}) == $i-1;
4372 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4376 #update conf after each succesfull cpu unplug
4377 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4378 PVE::QemuConfig->write_config($vmid, $conf);
4381 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4387 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4388 die "vcpus in running vm does not match its configuration\n"
4389 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4391 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4393 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4394 my $cpustr = print_cpu_device($conf, $i);
4395 qemu_deviceadd($vmid, $cpustr);
4398 my $currentrunningvcpus = undef;
4400 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4401 last if scalar(@{$currentrunningvcpus}) == $i;
4402 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4406 #update conf after each succesfull cpu hotplug
4407 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4408 PVE::QemuConfig->write_config($vmid, $conf);
4412 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4413 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4418 sub qemu_block_set_io_throttle {
4419 my ($vmid, $deviceid,
4420 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4421 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4422 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4423 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4425 return if !check_running($vmid) ;
4427 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4429 bps_rd => int($bps_rd),
4430 bps_wr => int($bps_wr),
4432 iops_rd => int($iops_rd),
4433 iops_wr => int($iops_wr),
4434 bps_max => int($bps_max),
4435 bps_rd_max => int($bps_rd_max),
4436 bps_wr_max => int($bps_wr_max),
4437 iops_max => int($iops_max),
4438 iops_rd_max => int($iops_rd_max),
4439 iops_wr_max => int($iops_wr_max),
4440 bps_max_length => int($bps_max_length),
4441 bps_rd_max_length => int($bps_rd_max_length),
4442 bps_wr_max_length => int($bps_wr_max_length),
4443 iops_max_length => int($iops_max_length),
4444 iops_rd_max_length => int($iops_rd_max_length),
4445 iops_wr_max_length => int($iops_wr_max_length),
4450 # old code, only used to shutdown old VM after update
4452 my ($fh, $timeout) = @_;
4454 my $sel = new IO::Select;
4461 while (scalar (@ready = $sel->can_read($timeout))) {
4463 if ($count = $fh->sysread($buf, 8192)) {
4464 if ($buf =~ /^(.*)\(qemu\) $/s) {
4471 if (!defined($count)) {
4478 die "monitor read timeout\n" if !scalar(@ready);
4483 sub qemu_block_resize {
4484 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4486 my $running = check_running($vmid);
4488 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4490 return if !$running;
4492 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4496 sub qemu_volume_snapshot {
4497 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4499 my $running = check_running($vmid);
4501 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4502 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4504 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4508 sub qemu_volume_snapshot_delete {
4509 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4511 my $running = check_running($vmid);
4516 my $conf = PVE::QemuConfig->load_config($vmid);
4517 foreach_drive($conf, sub {
4518 my ($ds, $drive) = @_;
4519 $running = 1 if $drive->{file} eq $volid;
4523 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4524 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4526 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4530 sub set_migration_caps {
4536 "auto-converge" => 1,
4538 "x-rdma-pin-all" => 0,
4543 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4545 for my $supported_capability (@$supported_capabilities) {
4547 capability => $supported_capability->{capability},
4548 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4552 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4555 my $fast_plug_option = {
4563 'vmstatestorage
' => 1,
4566 # hotplug changes in [PENDING]
4567 # $selection hash can be used to only apply specified options, for
4568 # example: { cores => 1 } (only apply changed 'cores
')
4569 # $errors ref is used to return error messages
4570 sub vmconfig_hotplug_pending {
4571 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4573 my $defaults = load_defaults();
4574 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4576 # commit values which do not have any impact on running VM first
4577 # Note: those option cannot raise errors, we we do not care about
4578 # $selection and always apply them.
4580 my $add_error = sub {
4581 my ($opt, $msg) = @_;
4582 $errors->{$opt} = "hotplug problem - $msg";
4586 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4587 if ($fast_plug_option->{$opt}) {
4588 $conf->{$opt} = $conf->{pending}->{$opt};
4589 delete $conf->{pending}->{$opt};
4595 PVE::QemuConfig->write_config($vmid, $conf);
4596 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4599 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4601 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4602 while (my ($opt, $force) = each %$pending_delete_hash) {
4603 next if $selection && !$selection->{$opt};
4605 if ($opt eq 'hotplug
') {
4606 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4607 } elsif ($opt eq 'tablet
') {
4608 die "skip\n" if !$hotplug_features->{usb};
4609 if ($defaults->{tablet}) {
4610 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4611 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4612 if $arch eq 'aarch64
';
4614 vm_deviceunplug($vmid, $conf, 'tablet
');
4615 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4617 } elsif ($opt =~ m/^usb\d+/) {
4619 # since we cannot reliably hot unplug usb devices
4620 # we are disabling it
4621 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4622 vm_deviceunplug($vmid, $conf, $opt);
4623 } elsif ($opt eq 'vcpus
') {
4624 die "skip\n" if !$hotplug_features->{cpu};
4625 qemu_cpu_hotplug($vmid, $conf, undef);
4626 } elsif ($opt eq 'balloon
') {
4627 # enable balloon device is not hotpluggable
4628 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4629 # here we reset the ballooning value to memory
4630 my $balloon = $conf->{memory} || $defaults->{memory};
4631 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4632 } elsif ($fast_plug_option->{$opt}) {
4634 } elsif ($opt =~ m/^net(\d+)$/) {
4635 die "skip\n" if !$hotplug_features->{network};
4636 vm_deviceunplug($vmid, $conf, $opt);
4637 } elsif (is_valid_drivename($opt)) {
4638 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4639 vm_deviceunplug($vmid, $conf, $opt);
4640 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4641 } elsif ($opt =~ m/^memory$/) {
4642 die "skip\n" if !$hotplug_features->{memory};
4643 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4644 } elsif ($opt eq 'cpuunits
') {
4645 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4646 } elsif ($opt eq 'cpulimit
') {
4647 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4653 &$add_error($opt, $err) if $err ne "skip\n";
4655 # save new config if hotplug was successful
4656 delete $conf->{$opt};
4657 vmconfig_undelete_pending_option($conf, $opt);
4658 PVE::QemuConfig->write_config($vmid, $conf);
4659 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4663 my $apply_pending_cloudinit;
4664 $apply_pending_cloudinit = sub {
4665 my ($key, $value) = @_;
4666 $apply_pending_cloudinit = sub {}; # once is enough
4668 my @cloudinit_opts = keys %$confdesc_cloudinit;
4669 foreach my $opt (keys %{$conf->{pending}}) {
4670 next if !grep { $_ eq $opt } @cloudinit_opts;
4671 $conf->{$opt} = delete $conf->{pending}->{$opt};
4674 my $new_conf = { %$conf };
4675 $new_conf->{$key} = $value;
4676 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4679 foreach my $opt (keys %{$conf->{pending}}) {
4680 next if $selection && !$selection->{$opt};
4681 my $value = $conf->{pending}->{$opt};
4683 if ($opt eq 'hotplug
') {
4684 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4685 } elsif ($opt eq 'tablet
') {
4686 die "skip\n" if !$hotplug_features->{usb};
4688 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4689 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4690 if $arch eq 'aarch64
';
4691 } elsif ($value == 0) {
4692 vm_deviceunplug($vmid, $conf, 'tablet
');
4693 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4695 } elsif ($opt =~ m/^usb\d+$/) {
4697 # since we cannot reliably hot unplug usb devices
4698 # we are disabling it
4699 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4700 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4701 die "skip\n" if !$d;
4702 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4703 } elsif ($opt eq 'vcpus
') {
4704 die "skip\n" if !$hotplug_features->{cpu};
4705 qemu_cpu_hotplug($vmid, $conf, $value);
4706 } elsif ($opt eq 'balloon
') {
4707 # enable/disable balloning device is not hotpluggable
4708 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4709 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4710 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4712 # allow manual ballooning if shares is set to zero
4713 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4714 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4715 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4717 } elsif ($opt =~ m/^net(\d+)$/) {
4718 # some changes can be done without hotplug
4719 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4720 $vmid, $opt, $value, $arch, $machine_type);
4721 } elsif (is_valid_drivename($opt)) {
4722 # some changes can be done without hotplug
4723 my $drive = parse_drive($opt, $value);
4724 if (drive_is_cloudinit($drive)) {
4725 &$apply_pending_cloudinit($opt, $value);
4727 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4728 $vmid, $opt, $value, 1, $arch, $machine_type);
4729 } elsif ($opt =~ m/^memory$/) { #dimms
4730 die "skip\n" if !$hotplug_features->{memory};
4731 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4732 } elsif ($opt eq 'cpuunits
') {
4733 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4734 } elsif ($opt eq 'cpulimit
') {
4735 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4736 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4738 die "skip\n"; # skip non-hot-pluggable options
4742 &$add_error($opt, $err) if $err ne "skip\n";
4744 # save new config if hotplug was successful
4745 $conf->{$opt} = $value;
4746 delete $conf->{pending}->{$opt};
4747 PVE::QemuConfig->write_config($vmid, $conf);
4748 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4753 sub try_deallocate_drive {
4754 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4756 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4757 my $volid = $drive->{file};
4758 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4759 my $sid = PVE::Storage::parse_volume_id($volid);
4760 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4762 # check if the disk is really unused
4763 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4764 if is_volume_in_use($storecfg, $conf, $key, $volid);
4765 PVE::Storage::vdisk_free($storecfg, $volid);
4768 # If vm is not owner of this disk remove from config
4776 sub vmconfig_delete_or_detach_drive {
4777 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4779 my $drive = parse_drive($opt, $conf->{$opt});
4781 my $rpcenv = PVE::RPCEnvironment::get();
4782 my $authuser = $rpcenv->get_user();
4785 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4786 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4788 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4792 sub vmconfig_apply_pending {
4793 my ($vmid, $conf, $storecfg) = @_;
4797 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4798 while (my ($opt, $force) = each %$pending_delete_hash) {
4799 die "internal error" if $opt =~ m/^unused/;
4800 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4801 if (!defined($conf->{$opt})) {
4802 vmconfig_undelete_pending_option($conf, $opt);
4803 PVE::QemuConfig->write_config($vmid, $conf);
4804 } elsif (is_valid_drivename($opt)) {
4805 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4806 vmconfig_undelete_pending_option($conf, $opt);
4807 delete $conf->{$opt};
4808 PVE::QemuConfig->write_config($vmid, $conf);
4810 vmconfig_undelete_pending_option($conf, $opt);
4811 delete $conf->{$opt};
4812 PVE::QemuConfig->write_config($vmid, $conf);
4816 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4818 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4819 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4821 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4822 # skip if nothing changed
4823 } elsif (is_valid_drivename($opt)) {
4824 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4825 if defined($conf->{$opt});
4826 $conf->{$opt} = $conf->{pending}->{$opt};
4828 $conf->{$opt} = $conf->{pending}->{$opt};
4831 delete $conf->{pending}->{$opt};
4832 PVE::QemuConfig->write_config($vmid, $conf);
4836 my $safe_num_ne = sub {
4839 return 0 if !defined($a) && !defined($b);
4840 return 1 if !defined($a);
4841 return 1 if !defined($b);
4846 my $safe_string_ne = sub {
4849 return 0 if !defined($a) && !defined($b);
4850 return 1 if !defined($a);
4851 return 1 if !defined($b);
4856 sub vmconfig_update_net {
4857 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4859 my $newnet = parse_net($value);
4861 if ($conf->{$opt}) {
4862 my $oldnet = parse_net($conf->{$opt});
4864 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4865 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4866 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4867 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4869 # for non online change, we try to hot-unplug
4870 die "skip\n" if !$hotplug;
4871 vm_deviceunplug($vmid, $conf, $opt);
4874 die "internal error" if $opt !~ m/net(\d+)/;
4875 my $iface = "tap${vmid}i$1";
4877 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4878 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4879 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4880 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4881 PVE::Network::tap_unplug($iface);
4882 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4883 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4884 # Rate can be applied on its own but any change above needs to
4885 # include the rate in tap_plug since OVS resets everything.
4886 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4889 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4890 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4898 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4904 sub vmconfig_update_disk {
4905 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
4907 # fixme: do we need force?
4909 my $drive = parse_drive($opt, $value);
4911 if ($conf->{$opt}) {
4913 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4915 my $media = $drive->{media} || 'disk
';
4916 my $oldmedia = $old_drive->{media} || 'disk
';
4917 die "unable to change media type\n" if $media ne $oldmedia;
4919 if (!drive_is_cdrom($old_drive)) {
4921 if ($drive->{file} ne $old_drive->{file}) {
4923 die "skip\n" if !$hotplug;
4925 # unplug and register as unused
4926 vm_deviceunplug($vmid, $conf, $opt);
4927 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4930 # update existing disk
4932 # skip non hotpluggable value
4933 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4934 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4935 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4936 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4941 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4942 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4943 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4944 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4945 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4946 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4947 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4948 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4949 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4950 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4951 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4952 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4953 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4954 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4955 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4956 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4957 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4958 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4960 qemu_block_set_io_throttle($vmid,"drive-$opt",
4961 ($drive->{mbps} || 0)*1024*1024,
4962 ($drive->{mbps_rd} || 0)*1024*1024,
4963 ($drive->{mbps_wr} || 0)*1024*1024,
4964 $drive->{iops} || 0,
4965 $drive->{iops_rd} || 0,
4966 $drive->{iops_wr} || 0,
4967 ($drive->{mbps_max} || 0)*1024*1024,
4968 ($drive->{mbps_rd_max} || 0)*1024*1024,
4969 ($drive->{mbps_wr_max} || 0)*1024*1024,
4970 $drive->{iops_max} || 0,
4971 $drive->{iops_rd_max} || 0,
4972 $drive->{iops_wr_max} || 0,
4973 $drive->{bps_max_length} || 1,
4974 $drive->{bps_rd_max_length} || 1,
4975 $drive->{bps_wr_max_length} || 1,
4976 $drive->{iops_max_length} || 1,
4977 $drive->{iops_rd_max_length} || 1,
4978 $drive->{iops_wr_max_length} || 1);
4987 if ($drive->{file} eq 'none
') {
4988 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4989 if (drive_is_cloudinit($old_drive)) {
4990 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4993 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4994 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4995 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5003 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5005 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5006 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5010 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5011 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5013 PVE::QemuConfig->lock_config($vmid, sub {
5014 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5016 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5018 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5020 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5022 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5023 vmconfig_apply_pending($vmid, $conf, $storecfg);
5024 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5027 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5029 my $defaults = load_defaults();
5031 # set environment variable useful inside network script
5032 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5034 my $local_volumes = {};
5036 if ($targetstorage) {
5037 foreach_drive($conf, sub {
5038 my ($ds, $drive) = @_;
5040 return if drive_is_cdrom($drive);
5042 my $volid = $drive->{file};
5046 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5048 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5049 return if $scfg->{shared};
5050 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5055 foreach my $opt (sort keys %$local_volumes) {
5057 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5058 my $drive = parse_drive($opt, $conf->{$opt});
5060 #if remote storage is specified, use default format
5061 if ($targetstorage && $targetstorage ne "1") {
5062 $storeid = $targetstorage;
5063 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5064 $format = $defFormat;
5066 #else we use same format than original
5067 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5068 $format = qemu_img_format($scfg, $volid);
5071 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5072 my $newdrive = $drive;
5073 $newdrive->{format} = $format;
5074 $newdrive->{file} = $newvolid;
5075 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5076 $local_volumes->{$opt} = $drivestr;
5077 #pass drive to conf for command line
5078 $conf->{$opt} = $drivestr;
5082 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5084 my $migrate_port = 0;
5087 if ($statefile eq 'tcp
') {
5088 my $localip = "localhost";
5089 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5090 my $nodename = PVE::INotify::nodename();
5092 if (!defined($migration_type)) {
5093 if (defined($datacenterconf->{migration}->{type})) {
5094 $migration_type = $datacenterconf->{migration}->{type};
5096 $migration_type = 'secure
';
5100 if ($migration_type eq 'insecure
') {
5101 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5102 if ($migrate_network_addr) {
5103 $localip = $migrate_network_addr;
5105 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5108 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5111 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5112 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5113 $migrate_uri = "tcp:${localip}:${migrate_port}";
5114 push @$cmd, '-incoming
', $migrate_uri;
5117 } elsif ($statefile eq 'unix
') {
5118 # should be default for secure migrations as a ssh TCP forward
5119 # tunnel is not deterministic reliable ready and fails regurarly
5120 # to set up in time, so use UNIX socket forwards
5121 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5122 unlink $socket_addr;
5124 $migrate_uri = "unix:$socket_addr";
5126 push @$cmd, '-incoming
', $migrate_uri;
5130 push @$cmd, '-loadstate
', $statefile;
5137 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5138 my $d = parse_hostpci($conf->{"hostpci$i"});
5140 my $pcidevices = $d->{pciid};
5141 foreach my $pcidevice (@$pcidevices) {
5142 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
5144 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5145 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5146 die "no pci device info for device '$pciid'\n" if !$info;
5147 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5148 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5149 die "can
't reset pci device '$pciid'\n"
5150 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5154 PVE::Storage::activate_volumes($storecfg, $vollist);
5156 if (!check_running($vmid, 1)) {
5158 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5159 outfunc => sub {}, errfunc => sub {});
5163 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5164 : $defaults->{cpuunits};
5166 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5167 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5170 Slice => 'qemu
.slice
',
5172 CPUShares => $cpuunits
5175 if (my $cpulimit = $conf->{cpulimit}) {
5176 $properties{CPUQuota} = int($cpulimit * 100);
5178 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5180 my $run_qemu = sub {
5181 PVE::Tools::run_fork sub {
5182 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5183 run_command($cmd, %run_params);
5187 if ($conf->{hugepages}) {
5190 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5191 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5193 PVE::QemuServer::Memory::hugepages_mount();
5194 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5196 eval { $run_qemu->() };
5198 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5202 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5204 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5207 eval { $run_qemu->() };
5211 # deactivate volumes if start fails
5212 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5213 die "start failed: $err";
5216 print "migration listens on $migrate_uri\n" if $migrate_uri;
5218 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5219 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5223 #start nbd server for storage migration
5224 if ($targetstorage) {
5225 my $nodename = PVE::INotify::nodename();
5226 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5227 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5228 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5229 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5231 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5233 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5235 foreach my $opt (sort keys %$local_volumes) {
5236 my $volid = $local_volumes->{$opt};
5237 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5238 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5239 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5243 if ($migratedfrom) {
5245 set_migration_caps($vmid);
5250 print "spice listens on port $spice_port\n";
5251 if ($spice_ticket) {
5252 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5253 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5258 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5259 if !$statefile && $conf->{balloon};
5261 foreach my $opt (keys %$conf) {
5262 next if $opt !~ m/^net\d+$/;
5263 my $nicconf = parse_net($conf->{$opt});
5264 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5268 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5269 path => "machine/peripheral/balloon0",
5270 property => "guest-stats-polling-interval",
5271 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5277 my ($vmid, $execute, %params) = @_;
5279 my $cmd = { execute => $execute, arguments => \%params };
5280 vm_qmp_command($vmid, $cmd);
5283 sub vm_mon_cmd_nocheck {
5284 my ($vmid, $execute, %params) = @_;
5286 my $cmd = { execute => $execute, arguments => \%params };
5287 vm_qmp_command($vmid, $cmd, 1);
5290 sub vm_qmp_command {
5291 my ($vmid, $cmd, $nocheck) = @_;
5296 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5297 $timeout = $cmd->{arguments}->{timeout};
5298 delete $cmd->{arguments}->{timeout};
5302 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5303 my $sname = qmp_socket($vmid);
5304 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5305 my $qmpclient = PVE::QMPClient->new();
5307 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5309 die "unable to open monitor socket\n";
5313 syslog("err", "VM $vmid qmp command failed - $err");
5320 sub vm_human_monitor_command {
5321 my ($vmid, $cmdline) = @_;
5326 execute => 'human-monitor-command
',
5327 arguments => { 'command-line
' => $cmdline},
5330 return vm_qmp_command($vmid, $cmd);
5333 sub vm_commandline {
5334 my ($storecfg, $vmid) = @_;
5336 my $conf = PVE::QemuConfig->load_config($vmid);
5338 my $defaults = load_defaults();
5340 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5342 return PVE::Tools::cmd2string($cmd);
5346 my ($vmid, $skiplock) = @_;
5348 PVE::QemuConfig->lock_config($vmid, sub {
5350 my $conf = PVE::QemuConfig->load_config($vmid);
5352 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5354 vm_mon_cmd($vmid, "system_reset");
5358 sub get_vm_volumes {
5362 foreach_volid($conf, sub {
5363 my ($volid, $attr) = @_;
5365 return if $volid =~ m|^/|;
5367 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5370 push @$vollist, $volid;
5376 sub vm_stop_cleanup {
5377 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5382 my $vollist = get_vm_volumes($conf);
5383 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5386 foreach my $ext (qw(mon qmp pid vnc qga)) {
5387 unlink "/var/run/qemu-server/${vmid}.$ext";
5390 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5392 warn $@ if $@; # avoid errors - just warn
5395 # Note: use $nockeck to skip tests if VM configuration file exists.
5396 # We need that when migration VMs to other nodes (files already moved)
5397 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5399 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5401 $force = 1 if !defined($force) && !$shutdown;
5404 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5405 kill 15, $pid if $pid;
5406 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5407 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5411 PVE
::QemuConfig-
>lock_config($vmid, sub {
5413 my $pid = check_running
($vmid, $nocheck);
5418 $conf = PVE
::QemuConfig-
>load_config($vmid);
5419 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5420 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5421 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5422 $timeout = $opts->{down
} if $opts->{down
};
5426 $timeout = 60 if !defined($timeout);
5430 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5431 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5433 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5436 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5443 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5448 if ($count >= $timeout) {
5450 warn "VM still running - terminating now with SIGTERM\n";
5453 die "VM quit/powerdown failed - got timeout\n";
5456 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5461 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5464 die "VM quit/powerdown failed\n";
5472 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5477 if ($count >= $timeout) {
5478 warn "VM still running - terminating now with SIGKILL\n";
5483 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5488 my ($vmid, $skiplock) = @_;
5490 PVE
::QemuConfig-
>lock_config($vmid, sub {
5492 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5494 PVE
::QemuConfig-
>check_lock($conf)
5495 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5497 vm_mon_cmd
($vmid, "stop");
5502 my ($vmid, $skiplock, $nocheck) = @_;
5504 PVE
::QemuConfig-
>lock_config($vmid, sub {
5506 my $res = vm_mon_cmd
($vmid, 'query-status');
5507 my $resume_cmd = 'cont';
5509 if ($res->{status
} && $res->{status
} eq 'suspended') {
5510 $resume_cmd = 'system_wakeup';
5515 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5517 PVE
::QemuConfig-
>check_lock($conf)
5518 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5520 vm_mon_cmd
($vmid, $resume_cmd);
5523 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5529 my ($vmid, $skiplock, $key) = @_;
5531 PVE
::QemuConfig-
>lock_config($vmid, sub {
5533 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5535 # there is no qmp command, so we use the human monitor command
5536 vm_human_monitor_command
($vmid, "sendkey $key");
5541 my ($storecfg, $vmid, $skiplock) = @_;
5543 PVE
::QemuConfig-
>lock_config($vmid, sub {
5545 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5547 if (!check_running
($vmid)) {
5548 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5550 die "VM $vmid is running - destroy failed\n";
5555 # vzdump restore implementaion
5557 sub tar_archive_read_firstfile
{
5558 my $archive = shift;
5560 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5562 # try to detect archive type first
5563 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5564 die "unable to open file '$archive'\n";
5565 my $firstfile = <$fh>;
5569 die "ERROR: archive contaions no data\n" if !$firstfile;
5575 sub tar_restore_cleanup
{
5576 my ($storecfg, $statfile) = @_;
5578 print STDERR
"starting cleanup\n";
5580 if (my $fd = IO
::File-
>new($statfile, "r")) {
5581 while (defined(my $line = <$fd>)) {
5582 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5585 if ($volid =~ m
|^/|) {
5586 unlink $volid || die 'unlink failed\n';
5588 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5590 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5592 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5594 print STDERR
"unable to parse line in statfile - $line";
5601 sub restore_archive
{
5602 my ($archive, $vmid, $user, $opts) = @_;
5604 my $format = $opts->{format
};
5607 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5608 $format = 'tar' if !$format;
5610 } elsif ($archive =~ m/\.tar$/) {
5611 $format = 'tar' if !$format;
5612 } elsif ($archive =~ m/.tar.lzo$/) {
5613 $format = 'tar' if !$format;
5615 } elsif ($archive =~ m/\.vma$/) {
5616 $format = 'vma' if !$format;
5617 } elsif ($archive =~ m/\.vma\.gz$/) {
5618 $format = 'vma' if !$format;
5620 } elsif ($archive =~ m/\.vma\.lzo$/) {
5621 $format = 'vma' if !$format;
5624 $format = 'vma' if !$format; # default
5627 # try to detect archive format
5628 if ($format eq 'tar') {
5629 return restore_tar_archive
($archive, $vmid, $user, $opts);
5631 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5635 sub restore_update_config_line
{
5636 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5638 return if $line =~ m/^\#qmdump\#/;
5639 return if $line =~ m/^\#vzdump\#/;
5640 return if $line =~ m/^lock:/;
5641 return if $line =~ m/^unused\d+:/;
5642 return if $line =~ m/^parent:/;
5643 return if $line =~ m/^template:/; # restored VM is never a template
5645 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5646 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5647 # try to convert old 1.X settings
5648 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5649 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5650 my ($model, $macaddr) = split(/\=/, $devconfig);
5651 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5654 bridge
=> "vmbr$ind",
5655 macaddr
=> $macaddr,
5657 my $netstr = print_net
($net);
5659 print $outfd "net$cookie->{netcount}: $netstr\n";
5660 $cookie->{netcount
}++;
5662 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5663 my ($id, $netstr) = ($1, $2);
5664 my $net = parse_net
($netstr);
5665 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5666 $netstr = print_net
($net);
5667 print $outfd "$id: $netstr\n";
5668 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5671 my $di = parse_drive
($virtdev, $value);
5672 if (defined($di->{backup
}) && !$di->{backup
}) {
5673 print $outfd "#$line";
5674 } elsif ($map->{$virtdev}) {
5675 delete $di->{format
}; # format can change on restore
5676 $di->{file
} = $map->{$virtdev};
5677 $value = print_drive
($vmid, $di);
5678 print $outfd "$virtdev: $value\n";
5682 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5684 if ($vmgenid ne '0') {
5685 # always generate a new vmgenid if there was a valid one setup
5686 $vmgenid = generate_uuid
();
5688 print $outfd "vmgenid: $vmgenid\n";
5689 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5690 my ($uuid, $uuid_str);
5691 UUID
::generate
($uuid);
5692 UUID
::unparse
($uuid, $uuid_str);
5693 my $smbios1 = parse_smbios1
($2);
5694 $smbios1->{uuid
} = $uuid_str;
5695 print $outfd $1.print_smbios1
($smbios1)."\n";
5702 my ($cfg, $vmid) = @_;
5704 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5706 my $volid_hash = {};
5707 foreach my $storeid (keys %$info) {
5708 foreach my $item (@{$info->{$storeid}}) {
5709 next if !($item->{volid
} && $item->{size
});
5710 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5711 $volid_hash->{$item->{volid
}} = $item;
5718 sub is_volume_in_use
{
5719 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5721 my $path = PVE
::Storage
::path
($storecfg, $volid);
5723 my $scan_config = sub {
5724 my ($cref, $snapname) = @_;
5726 foreach my $key (keys %$cref) {
5727 my $value = $cref->{$key};
5728 if (is_valid_drivename
($key)) {
5729 next if $skip_drive && $key eq $skip_drive;
5730 my $drive = parse_drive
($key, $value);
5731 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5732 return 1 if $volid eq $drive->{file
};
5733 if ($drive->{file
} =~ m!^/!) {
5734 return 1 if $drive->{file
} eq $path;
5736 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5738 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5740 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5748 return 1 if &$scan_config($conf);
5752 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5753 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5759 sub update_disksize
{
5760 my ($vmid, $conf, $volid_hash) = @_;
5763 my $prefix = "VM $vmid:";
5765 # used and unused disks
5766 my $referenced = {};
5768 # Note: it is allowed to define multiple storages with same path (alias), so
5769 # we need to check both 'volid' and real 'path' (two different volid can point
5770 # to the same path).
5772 my $referencedpath = {};
5775 foreach my $opt (keys %$conf) {
5776 if (is_valid_drivename
($opt)) {
5777 my $drive = parse_drive
($opt, $conf->{$opt});
5778 my $volid = $drive->{file
};
5781 $referenced->{$volid} = 1;
5782 if ($volid_hash->{$volid} &&
5783 (my $path = $volid_hash->{$volid}->{path
})) {
5784 $referencedpath->{$path} = 1;
5787 next if drive_is_cdrom
($drive);
5788 next if !$volid_hash->{$volid};
5790 $drive->{size
} = $volid_hash->{$volid}->{size
};
5791 my $new = print_drive
($vmid, $drive);
5792 if ($new ne $conf->{$opt}) {
5794 $conf->{$opt} = $new;
5795 print "$prefix update disk '$opt' information.\n";
5800 # remove 'unusedX' entry if volume is used
5801 foreach my $opt (keys %$conf) {
5802 next if $opt !~ m/^unused\d+$/;
5803 my $volid = $conf->{$opt};
5804 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5805 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5806 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5808 delete $conf->{$opt};
5811 $referenced->{$volid} = 1;
5812 $referencedpath->{$path} = 1 if $path;
5815 foreach my $volid (sort keys %$volid_hash) {
5816 next if $volid =~ m/vm-$vmid-state-/;
5817 next if $referenced->{$volid};
5818 my $path = $volid_hash->{$volid}->{path
};
5819 next if !$path; # just to be sure
5820 next if $referencedpath->{$path};
5822 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5823 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5824 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5831 my ($vmid, $nolock, $dryrun) = @_;
5833 my $cfg = PVE
::Storage
::config
();
5835 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5836 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5837 foreach my $stor (keys %{$cfg->{ids
}}) {
5838 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5841 print "rescan volumes...\n";
5842 my $volid_hash = scan_volids
($cfg, $vmid);
5844 my $updatefn = sub {
5847 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5849 PVE
::QemuConfig-
>check_lock($conf);
5852 foreach my $volid (keys %$volid_hash) {
5853 my $info = $volid_hash->{$volid};
5854 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5857 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5859 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5862 if (defined($vmid)) {
5866 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5869 my $vmlist = config_list
();
5870 foreach my $vmid (keys %$vmlist) {
5874 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5880 sub restore_vma_archive
{
5881 my ($archive, $vmid, $user, $opts, $comp) = @_;
5883 my $readfrom = $archive;
5885 my $cfg = PVE
::Storage
::config
();
5887 my $bwlimit = $opts->{bwlimit
};
5889 my $dbg_cmdstring = '';
5890 my $add_pipe = sub {
5892 push @$commands, $cmd;
5893 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5894 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5899 if ($archive eq '-') {
5902 # If we use a backup from a PVE defined storage we also consider that
5903 # storage's rate limit:
5904 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5905 if (defined($volid)) {
5906 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5907 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5909 print STDERR
"applying read rate limit: $readlimit\n";
5910 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5911 $add_pipe->($cstream);
5918 if ($comp eq 'gzip') {
5919 $cmd = ['zcat', $readfrom];
5920 } elsif ($comp eq 'lzop') {
5921 $cmd = ['lzop', '-d', '-c', $readfrom];
5923 die "unknown compression method '$comp'\n";
5928 my $tmpdir = "/var/tmp/vzdumptmp$$";
5931 # disable interrupts (always do cleanups)
5935 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5937 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5938 POSIX
::mkfifo
($mapfifo, 0600);
5941 my $openfifo = sub {
5942 open($fifofh, '>', $mapfifo) || die $!;
5945 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5952 my $rpcenv = PVE
::RPCEnvironment
::get
();
5954 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5955 my $tmpfn = "$conffile.$$.tmp";
5957 # Note: $oldconf is undef if VM does not exists
5958 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5959 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5963 my $print_devmap = sub {
5964 my $virtdev_hash = {};
5966 my $cfgfn = "$tmpdir/qemu-server.conf";
5968 # we can read the config - that is already extracted
5969 my $fh = IO
::File-
>new($cfgfn, "r") ||
5970 "unable to read qemu-server.conf - $!\n";
5972 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5974 my $pve_firewall_dir = '/etc/pve/firewall';
5975 mkdir $pve_firewall_dir; # make sure the dir exists
5976 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5979 while (defined(my $line = <$fh>)) {
5980 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5981 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5982 die "archive does not contain data for drive '$virtdev'\n"
5983 if !$devinfo->{$devname};
5984 if (defined($opts->{storage
})) {
5985 $storeid = $opts->{storage
} || 'local';
5986 } elsif (!$storeid) {
5989 $format = 'raw' if !$format;
5990 $devinfo->{$devname}->{devname
} = $devname;
5991 $devinfo->{$devname}->{virtdev
} = $virtdev;
5992 $devinfo->{$devname}->{format
} = $format;
5993 $devinfo->{$devname}->{storeid
} = $storeid;
5995 # check permission on storage
5996 my $pool = $opts->{pool
}; # todo: do we need that?
5997 if ($user ne 'root@pam') {
5998 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6001 $storage_limits{$storeid} = $bwlimit;
6003 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6007 foreach my $key (keys %storage_limits) {
6008 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6010 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6011 $storage_limits{$key} = $limit * 1024;
6014 foreach my $devname (keys %$devinfo) {
6015 die "found no device mapping information for device '$devname'\n"
6016 if !$devinfo->{$devname}->{virtdev
};
6019 # create empty/temp config
6021 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6022 foreach_drive
($oldconf, sub {
6023 my ($ds, $drive) = @_;
6025 return if drive_is_cdrom
($drive);
6027 my $volid = $drive->{file
};
6029 return if !$volid || $volid =~ m
|^/|;
6031 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6032 return if !$path || !$owner || ($owner != $vmid);
6034 # Note: only delete disk we want to restore
6035 # other volumes will become unused
6036 if ($virtdev_hash->{$ds}) {
6037 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6044 # delete vmstate files
6045 # since after the restore we have no snapshots anymore
6046 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6047 my $snap = $oldconf->{snapshots
}->{$snapname};
6048 if ($snap->{vmstate
}) {
6049 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6058 foreach my $virtdev (sort keys %$virtdev_hash) {
6059 my $d = $virtdev_hash->{$virtdev};
6060 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6061 my $storeid = $d->{storeid
};
6062 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6065 if (my $limit = $storage_limits{$storeid}) {
6066 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6069 # test if requested format is supported
6070 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6071 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6072 $d->{format
} = $defFormat if !$supported;
6074 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6075 $d->{format
}, undef, $alloc_size);
6076 print STDERR
"new volume ID is '$volid'\n";
6077 $d->{volid
} = $volid;
6078 my $path = PVE
::Storage
::path
($cfg, $volid);
6080 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6082 my $write_zeros = 1;
6083 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6087 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6089 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6090 $map->{$virtdev} = $volid;
6093 $fh->seek(0, 0) || die "seek failed - $!\n";
6095 my $outfd = new IO
::File
($tmpfn, "w") ||
6096 die "unable to write config for VM $vmid\n";
6098 my $cookie = { netcount
=> 0 };
6099 while (defined(my $line = <$fh>)) {
6100 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6113 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6114 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6116 $oldtimeout = alarm($timeout);
6123 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6124 my ($dev_id, $size, $devname) = ($1, $2, $3);
6125 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6126 } elsif ($line =~ m/^CTIME: /) {
6127 # we correctly received the vma config, so we can disable
6128 # the timeout now for disk allocation (set to 10 minutes, so
6129 # that we always timeout if something goes wrong)
6132 print $fifofh "done\n";
6133 my $tmp = $oldtimeout || 0;
6134 $oldtimeout = undef;
6140 print "restore vma archive: $dbg_cmdstring\n";
6141 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6145 alarm($oldtimeout) if $oldtimeout;
6148 foreach my $devname (keys %$devinfo) {
6149 my $volid = $devinfo->{$devname}->{volid
};
6150 push @$vollist, $volid if $volid;
6153 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6161 foreach my $devname (keys %$devinfo) {
6162 my $volid = $devinfo->{$devname}->{volid
};
6165 if ($volid =~ m
|^/|) {
6166 unlink $volid || die 'unlink failed\n';
6168 PVE
::Storage
::vdisk_free
($cfg, $volid);
6170 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6172 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6179 rename($tmpfn, $conffile) ||
6180 die "unable to commit configuration file '$conffile'\n";
6182 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6184 eval { rescan
($vmid, 1); };
6188 sub restore_tar_archive
{
6189 my ($archive, $vmid, $user, $opts) = @_;
6191 if ($archive ne '-') {
6192 my $firstfile = tar_archive_read_firstfile
($archive);
6193 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6194 if $firstfile ne 'qemu-server.conf';
6197 my $storecfg = PVE
::Storage
::config
();
6199 # destroy existing data - keep empty config
6200 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6201 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6203 my $tocmd = "/usr/lib/qemu-server/qmextract";
6205 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6206 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6207 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6208 $tocmd .= ' --info' if $opts->{info
};
6210 # tar option "xf" does not autodetect compression when read from STDIN,
6211 # so we pipe to zcat
6212 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6213 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6215 my $tmpdir = "/var/tmp/vzdumptmp$$";
6218 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6219 local $ENV{VZDUMP_VMID
} = $vmid;
6220 local $ENV{VZDUMP_USER
} = $user;
6222 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6223 my $tmpfn = "$conffile.$$.tmp";
6225 # disable interrupts (always do cleanups)
6229 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6237 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6239 if ($archive eq '-') {
6240 print "extracting archive from STDIN\n";
6241 run_command
($cmd, input
=> "<&STDIN");
6243 print "extracting archive '$archive'\n";
6247 return if $opts->{info
};
6251 my $statfile = "$tmpdir/qmrestore.stat";
6252 if (my $fd = IO
::File-
>new($statfile, "r")) {
6253 while (defined (my $line = <$fd>)) {
6254 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6255 $map->{$1} = $2 if $1;
6257 print STDERR
"unable to parse line in statfile - $line\n";
6263 my $confsrc = "$tmpdir/qemu-server.conf";
6265 my $srcfd = new IO
::File
($confsrc, "r") ||
6266 die "unable to open file '$confsrc'\n";
6268 my $outfd = new IO
::File
($tmpfn, "w") ||
6269 die "unable to write config for VM $vmid\n";
6271 my $cookie = { netcount
=> 0 };
6272 while (defined (my $line = <$srcfd>)) {
6273 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6285 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6292 rename $tmpfn, $conffile ||
6293 die "unable to commit configuration file '$conffile'\n";
6295 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6297 eval { rescan
($vmid, 1); };
6301 sub foreach_storage_used_by_vm
{
6302 my ($conf, $func) = @_;
6306 foreach_drive
($conf, sub {
6307 my ($ds, $drive) = @_;
6308 return if drive_is_cdrom
($drive);
6310 my $volid = $drive->{file
};
6312 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6313 $sidhash->{$sid} = $sid if $sid;
6316 foreach my $sid (sort keys %$sidhash) {
6321 sub do_snapshots_with_qemu
{
6322 my ($storecfg, $volid) = @_;
6324 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6326 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6327 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6331 if ($volid =~ m/\.(qcow2|qed)$/){
6338 sub qga_check_running
{
6339 my ($vmid, $nowarn) = @_;
6341 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6343 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6349 sub template_create
{
6350 my ($vmid, $conf, $disk) = @_;
6352 my $storecfg = PVE
::Storage
::config
();
6354 foreach_drive
($conf, sub {
6355 my ($ds, $drive) = @_;
6357 return if drive_is_cdrom
($drive);
6358 return if $disk && $ds ne $disk;
6360 my $volid = $drive->{file
};
6361 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6363 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6364 $drive->{file
} = $voliddst;
6365 $conf->{$ds} = print_drive
($vmid, $drive);
6366 PVE
::QemuConfig-
>write_config($vmid, $conf);
6370 sub qemu_img_convert
{
6371 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6373 my $storecfg = PVE
::Storage
::config
();
6374 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6375 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6377 if ($src_storeid && $dst_storeid) {
6379 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6381 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6382 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6384 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6385 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6387 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6388 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6391 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6392 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6393 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6394 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6395 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6396 if ($is_zero_initialized) {
6397 push @$cmd, "zeroinit:$dst_path";
6399 push @$cmd, $dst_path;
6404 if($line =~ m/\((\S+)\/100\
%\)/){
6406 my $transferred = int($size * $percent / 100);
6407 my $remaining = $size - $transferred;
6409 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6414 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6416 die "copy failed: $err" if $err;
6420 sub qemu_img_format
{
6421 my ($scfg, $volname) = @_;
6423 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6430 sub qemu_drive_mirror
{
6431 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6433 $jobs = {} if !$jobs;
6437 $jobs->{"drive-$drive"} = {};
6439 if ($dst_volid =~ /^nbd:/) {
6440 $qemu_target = $dst_volid;
6443 my $storecfg = PVE
::Storage
::config
();
6444 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6446 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6448 $format = qemu_img_format
($dst_scfg, $dst_volname);
6450 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6452 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6455 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6456 $opts->{format
} = $format if $format;
6458 print "drive mirror is starting for drive-$drive\n";
6460 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6463 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6464 die "mirroring error: $err";
6467 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6470 sub qemu_drive_mirror_monitor
{
6471 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6474 my $err_complete = 0;
6477 die "storage migration timed out\n" if $err_complete > 300;
6479 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6481 my $running_mirror_jobs = {};
6482 foreach my $stat (@$stats) {
6483 next if $stat->{type
} ne 'mirror';
6484 $running_mirror_jobs->{$stat->{device
}} = $stat;
6487 my $readycounter = 0;
6489 foreach my $job (keys %$jobs) {
6491 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6492 print "$job : finished\n";
6493 delete $jobs->{$job};
6497 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6499 my $busy = $running_mirror_jobs->{$job}->{busy
};
6500 my $ready = $running_mirror_jobs->{$job}->{ready
};
6501 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6502 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6503 my $remaining = $total - $transferred;
6504 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6506 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6509 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6512 last if scalar(keys %$jobs) == 0;
6514 if ($readycounter == scalar(keys %$jobs)) {
6515 print "all mirroring jobs are ready \n";
6516 last if $skipcomplete; #do the complete later
6518 if ($vmiddst && $vmiddst != $vmid) {
6519 my $agent_running = $qga && qga_check_running
($vmid);
6520 if ($agent_running) {
6521 print "freeze filesystem\n";
6522 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6524 print "suspend vm\n";
6525 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6528 # if we clone a disk for a new target vm, we don't switch the disk
6529 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6531 if ($agent_running) {
6532 print "unfreeze filesystem\n";
6533 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6535 print "resume vm\n";
6536 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6542 foreach my $job (keys %$jobs) {
6543 # try to switch the disk if source and destination are on the same guest
6544 print "$job: Completing block job...\n";
6546 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6547 if ($@ =~ m/cannot be completed/) {
6548 print "$job: Block job cannot be completed, try again.\n";
6551 print "$job: Completed successfully.\n";
6552 $jobs->{$job}->{complete
} = 1;
6563 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6564 die "mirroring error: $err";
6569 sub qemu_blockjobs_cancel
{
6570 my ($vmid, $jobs) = @_;
6572 foreach my $job (keys %$jobs) {
6573 print "$job: Cancelling block job\n";
6574 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6575 $jobs->{$job}->{cancel
} = 1;
6579 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6581 my $running_jobs = {};
6582 foreach my $stat (@$stats) {
6583 $running_jobs->{$stat->{device
}} = $stat;
6586 foreach my $job (keys %$jobs) {
6588 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6589 print "$job: Done.\n";
6590 delete $jobs->{$job};
6594 last if scalar(keys %$jobs) == 0;
6601 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6602 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6607 print "create linked clone of drive $drivename ($drive->{file})\n";
6608 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6609 push @$newvollist, $newvolid;
6612 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6613 $storeid = $storage if $storage;
6615 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6616 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6618 print "create full clone of drive $drivename ($drive->{file})\n";
6620 if (drive_is_cloudinit
($drive)) {
6621 $name = "vm-$newvmid-cloudinit";
6622 # cloudinit only supports raw and qcow2 atm:
6623 if ($dst_format eq 'qcow2') {
6625 } elsif ($dst_format ne 'raw') {
6626 die "clone: unhandled format for cloudinit image\n";
6629 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6630 push @$newvollist, $newvolid;
6632 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6634 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6635 if (!$running || $snapname) {
6636 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6639 my $kvmver = get_running_qemu_version
($vmid);
6640 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6641 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6642 if $drive->{iothread
};
6645 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6649 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6652 $disk->{format
} = undef;
6653 $disk->{file
} = $newvolid;
6654 $disk->{size
} = $size;
6659 # this only works if VM is running
6660 sub get_current_qemu_machine
{
6663 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6664 my $res = vm_qmp_command
($vmid, $cmd);
6666 my ($current, $default);
6667 foreach my $e (@$res) {
6668 $default = $e->{name
} if $e->{'is-default'};
6669 $current = $e->{name
} if $e->{'is-current'};
6672 # fallback to the default machine if current is not supported by qemu
6673 return $current || $default || 'pc';
6676 sub get_running_qemu_version
{
6678 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6679 my $res = vm_qmp_command
($vmid, $cmd);
6680 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6683 sub qemu_machine_feature_enabled
{
6684 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6689 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6691 $current_major = $3;
6692 $current_minor = $4;
6694 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6696 $current_major = $1;
6697 $current_minor = $2;
6700 return 1 if $current_major > $version_major ||
6701 ($current_major == $version_major &&
6702 $current_minor >= $version_minor);
6705 sub qemu_machine_pxe
{
6706 my ($vmid, $conf, $machine) = @_;
6708 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6710 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6717 sub qemu_use_old_bios_files
{
6718 my ($machine_type) = @_;
6720 return if !$machine_type;
6722 my $use_old_bios_files = undef;
6724 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6726 $use_old_bios_files = 1;
6728 my $kvmver = kvm_user_version
();
6729 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6730 # load new efi bios files on migration. So this hack is required to allow
6731 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6732 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6733 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6736 return ($use_old_bios_files, $machine_type);
6739 sub create_efidisk
($$$$$) {
6740 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6742 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6743 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6745 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6746 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6747 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6749 my $path = PVE
::Storage
::path
($storecfg, $volid);
6751 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6753 die "Copying EFI vars image failed: $@" if $@;
6755 return ($volid, $vars_size);
6758 sub vm_iothreads_list
{
6761 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6764 foreach my $iothread (@$res) {
6765 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6772 my ($conf, $drive) = @_;
6776 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6778 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6784 my $controller = int($drive->{index} / $maxdev);
6785 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6787 return ($maxdev, $controller, $controller_prefix);
6790 sub add_hyperv_enlightenments
{
6791 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6793 return if $winversion < 6;
6794 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6796 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6798 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6799 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6800 push @$cpuFlags , 'hv_vapic';
6801 push @$cpuFlags , 'hv_time';
6803 push @$cpuFlags , 'hv_spinlocks=0xffff';
6806 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6807 push @$cpuFlags , 'hv_reset';
6808 push @$cpuFlags , 'hv_vpindex';
6809 push @$cpuFlags , 'hv_runtime';
6812 if ($winversion >= 7) {
6813 push @$cpuFlags , 'hv_relaxed';
6815 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6816 push @$cpuFlags , 'hv_synic';
6817 push @$cpuFlags , 'hv_stimer';
6822 sub windows_version
{
6825 return 0 if !$ostype;
6829 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6831 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6833 } elsif ($ostype =~ m/^win(\d+)$/) {
6840 sub resolve_dst_disk_format
{
6841 my ($storecfg, $storeid, $src_volname, $format) = @_;
6842 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6845 # if no target format is specified, use the source disk format as hint
6847 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6848 $format = qemu_img_format
($scfg, $src_volname);
6854 # test if requested format is supported - else use default
6855 my $supported = grep { $_ eq $format } @$validFormats;
6856 $format = $defFormat if !$supported;
6860 sub resolve_first_disk
{
6862 my @disks = PVE
::QemuServer
::valid_drive_names
();
6864 foreach my $ds (reverse @disks) {
6865 next if !$conf->{$ds};
6866 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6867 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6874 my ($uuid, $uuid_str);
6875 UUID
::generate
($uuid);
6876 UUID
::unparse
($uuid, $uuid_str);
6880 sub generate_smbios1_uuid
{
6881 return "uuid=".generate_uuid
();
6887 vm_mon_cmd
($vmid, 'nbd-server-stop');
6890 # bash completion helper
6892 sub complete_backup_archives
{
6893 my ($cmdname, $pname, $cvalue) = @_;
6895 my $cfg = PVE
::Storage
::config
();
6899 if ($cvalue =~ m/^([^:]+):/) {
6903 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6906 foreach my $id (keys %$data) {
6907 foreach my $item (@{$data->{$id}}) {
6908 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6909 push @$res, $item->{volid
} if defined($item->{volid
});
6916 my $complete_vmid_full = sub {
6919 my $idlist = vmstatus
();
6923 foreach my $id (keys %$idlist) {
6924 my $d = $idlist->{$id};
6925 if (defined($running)) {
6926 next if $d->{template
};
6927 next if $running && $d->{status
} ne 'running';
6928 next if !$running && $d->{status
} eq 'running';
6937 return &$complete_vmid_full();
6940 sub complete_vmid_stopped
{
6941 return &$complete_vmid_full(0);
6944 sub complete_vmid_running
{
6945 return &$complete_vmid_full(1);
6948 sub complete_storage
{
6950 my $cfg = PVE
::Storage
::config
();
6951 my $ids = $cfg->{ids
};
6954 foreach my $sid (keys %$ids) {
6955 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6956 next if !$ids->{$sid}->{content
}->{images
};