1 package PVE
::QemuServer
;
22 use Storable
qw(dclone);
23 use PVE
::Exception
qw(raise raise_param_exc);
25 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
26 use PVE
::JSONSchema
qw(get_standard_option);
27 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
32 use PVE
::RPCEnvironment
;
33 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr);
34 use PVE
::QemuServer
::Memory
;
35 use PVE
::QemuServer
::USB
qw(parse_usb_device);
36 use PVE
::QemuServer
::Cloudinit
;
39 use Time
::HiRes
qw(gettimeofday);
40 use File
::Copy
qw(copy);
43 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
46 "$EDK2_FW_BASE/OVMF_CODE.fd",
47 "$EDK2_FW_BASE/OVMF_VARS.fd"
50 "$EDK2_FW_BASE/AAVMF_CODE.fd",
51 "$EDK2_FW_BASE/AAVMF_VARS.fd"
55 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
57 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
59 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
61 # Note about locking: we use flock on the config file protect
62 # against concurent actions.
63 # Aditionaly, we have a 'lock' setting in the config file. This
64 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
65 # allowed when such lock is set. But you can ignore this kind of
66 # lock with the --skiplock flag.
68 cfs_register_file
('/qemu-server/',
72 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
73 description
=> "Some command save/restore state from this location.",
79 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
80 description
=> "The name of the snapshot.",
81 type
=> 'string', format
=> 'pve-configid',
85 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
87 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
88 description
=> "The drive's backing file's data format.",
92 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
93 description
=> "Specifies the Qemu machine type.",
95 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
100 #no warnings 'redefine';
103 my ($controller, $vmid, $option, $value) = @_;
105 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
106 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
110 my $nodename = PVE
::INotify
::nodename
();
112 mkdir "/etc/pve/nodes/$nodename";
113 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
116 my $var_run_tmpdir = "/var/run/qemu-server";
117 mkdir $var_run_tmpdir;
119 my $lock_dir = "/var/lock/qemu-server";
122 my $cpu_vendor_list = {
124 486 => 'GenuineIntel',
125 pentium
=> 'GenuineIntel',
126 pentium2
=> 'GenuineIntel',
127 pentium3
=> 'GenuineIntel',
128 coreduo
=> 'GenuineIntel',
129 core2duo
=> 'GenuineIntel',
130 Conroe
=> 'GenuineIntel',
131 Penryn
=> 'GenuineIntel',
132 Nehalem
=> 'GenuineIntel',
133 'Nehalem-IBRS' => 'GenuineIntel',
134 Westmere
=> 'GenuineIntel',
135 'Westmere-IBRS' => 'GenuineIntel',
136 SandyBridge
=> 'GenuineIntel',
137 'SandyBridge-IBRS' => 'GenuineIntel',
138 IvyBridge
=> 'GenuineIntel',
139 'IvyBridge-IBRS' => 'GenuineIntel',
140 Haswell
=> 'GenuineIntel',
141 'Haswell-IBRS' => 'GenuineIntel',
142 'Haswell-noTSX' => 'GenuineIntel',
143 'Haswell-noTSX-IBRS' => 'GenuineIntel',
144 Broadwell
=> 'GenuineIntel',
145 'Broadwell-IBRS' => 'GenuineIntel',
146 'Broadwell-noTSX' => 'GenuineIntel',
147 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
148 'Skylake-Client' => 'GenuineIntel',
149 'Skylake-Client-IBRS' => 'GenuineIntel',
150 'Skylake-Server' => 'GenuineIntel',
151 'Skylake-Server-IBRS' => 'GenuineIntel',
154 athlon
=> 'AuthenticAMD',
155 phenom
=> 'AuthenticAMD',
156 Opteron_G1
=> 'AuthenticAMD',
157 Opteron_G2
=> 'AuthenticAMD',
158 Opteron_G3
=> 'AuthenticAMD',
159 Opteron_G4
=> 'AuthenticAMD',
160 Opteron_G5
=> 'AuthenticAMD',
161 EPYC
=> 'AuthenticAMD',
162 'EPYC-IBPB' => 'AuthenticAMD',
164 # generic types, use vendor from host node
173 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
177 description
=> "Emulated CPU type.",
179 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
184 description
=> "Do not identify as a KVM virtual machine.",
190 description
=> "List of additional CPU flags separated by ';'."
191 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
192 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
193 format_description
=> '+FLAG[;-FLAG...]',
195 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
204 enum
=> [qw(i6300esb ib700)],
205 description
=> "Watchdog type to emulate.",
206 default => 'i6300esb',
211 enum
=> [qw(reset shutdown poweroff pause debug none)],
212 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
216 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
220 description
=> "Enable/disable Qemu GuestAgent.",
225 fstrim_cloned_disks
=> {
226 description
=> "Run fstrim after cloning/moving a disk.",
235 description
=> "Select the VGA type.",
240 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 serial0 serial1 serial2 serial3 std virtio vmware)],
243 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
255 description
=> "Specifies whether a VM will be started during system bootup.",
261 description
=> "Automatic restart after crash (currently ignored).",
266 type
=> 'string', format
=> 'pve-hotplug-features',
267 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'.",
268 default => 'network,disk,usb',
273 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
279 description
=> "Lock/unlock the VM.",
280 enum
=> [qw(migrate backup snapshot rollback)],
285 description
=> "Limit of CPU usage.",
286 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.",
294 description
=> "CPU weight for a VM.",
295 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.",
303 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
310 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
316 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.",
324 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
325 "It should not be necessary to set it.",
326 enum
=> PVE
::Tools
::kvmkeymaplist
(),
331 type
=> 'string', format
=> 'dns-name',
332 description
=> "Set a name for the VM. Only used on the configuration web interface.",
337 description
=> "SCSI controller model",
338 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
344 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
349 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
350 description
=> "Specify guest operating system.",
351 verbose_description
=> <<EODESC,
352 Specify guest operating system. This is used to enable special
353 optimization/features for specific operating systems:
356 other;; unspecified OS
357 wxp;; Microsoft Windows XP
358 w2k;; Microsoft Windows 2000
359 w2k3;; Microsoft Windows 2003
360 w2k8;; Microsoft Windows 2008
361 wvista;; Microsoft Windows Vista
362 win7;; Microsoft Windows 7
363 win8;; Microsoft Windows 8/2012/2012r2
364 win10;; Microsoft Windows 10/2016
365 l24;; Linux 2.4 Kernel
366 l26;; Linux 2.6/3.X Kernel
367 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
373 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
374 pattern
=> '[acdn]{1,4}',
379 type
=> 'string', format
=> 'pve-qm-bootdisk',
380 description
=> "Enable booting from specified disk.",
381 pattern
=> '(ide|sata|scsi|virtio)\d+',
386 description
=> "The number of CPUs. Please use option -sockets instead.",
393 description
=> "The number of CPU sockets.",
400 description
=> "The number of cores per socket.",
407 description
=> "Enable/disable NUMA.",
413 description
=> "Enable/disable hugepages memory.",
414 enum
=> [qw(any 2 1024)],
419 description
=> "Number of hotplugged vcpus.",
426 description
=> "Enable/disable ACPI.",
431 description
=> "Enable/disable Qemu GuestAgent and its properties.",
433 format
=> $agent_fmt,
438 description
=> "Enable/disable KVM hardware virtualization.",
444 description
=> "Enable/disable time drift fix.",
450 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
455 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
459 type
=> 'string', format
=> $vga_fmt,
460 description
=> "Configure the VGA hardware.",
461 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
462 "high resolution modes (>= 1280x1024x16) you may need to increase " .
463 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
464 "is 'std' for all OS types besides some Windows versions (XP and " .
465 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
466 "display server. For win* OS you can select how many independent " .
467 "displays you want, Linux guests can add displays them self.\n".
468 "You can also run without any graphic card, using a serial device as terminal.",
472 type
=> 'string', format
=> 'pve-qm-watchdog',
473 description
=> "Create a virtual hardware watchdog device.",
474 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
475 " (by a guest action), the watchdog must be periodically polled " .
476 "by an agent inside the guest or else the watchdog will reset " .
477 "the guest (or execute the respective action specified)",
482 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
483 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'.",
484 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
487 startup
=> get_standard_option
('pve-startup-order'),
491 description
=> "Enable/disable Template.",
497 description
=> "Arbitrary arguments passed to kvm.",
498 verbose_description
=> <<EODESCR,
499 Arbitrary arguments passed to kvm, for example:
501 args: -no-reboot -no-hpet
503 NOTE: this option is for experts only.
510 description
=> "Enable/disable the USB tablet device.",
511 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
512 "usually needed to allow absolute mouse positioning with VNC. " .
513 "Else the mouse runs out of sync with normal VNC clients. " .
514 "If you're running lots of console-only guests on one host, " .
515 "you may consider disabling this to save some context switches. " .
516 "This is turned off by default if you use spice (-vga=qxl).",
521 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
525 migrate_downtime
=> {
528 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
534 type
=> 'string', format
=> 'pve-qm-ide',
535 typetext
=> '<volume>',
536 description
=> "This is an alias for option -ide2",
540 description
=> "Emulated CPU type.",
544 parent
=> get_standard_option
('pve-snapshot-name', {
546 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
550 description
=> "Timestamp for snapshots.",
556 type
=> 'string', format
=> 'pve-volume-id',
557 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
559 vmstatestorage
=> get_standard_option
('pve-storage-id', {
560 description
=> "Default storage for VM state volumes/files.",
563 runningmachine
=> get_standard_option
('pve-qemu-machine', {
564 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
566 machine
=> get_standard_option
('pve-qemu-machine'),
568 description
=> "Virtual processor architecture. Defaults to the host.",
571 enum
=> [qw(x86_64 aarch64)],
574 description
=> "Specify SMBIOS type 1 fields.",
575 type
=> 'string', format
=> 'pve-qm-smbios1',
582 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
588 enum
=> [ qw(seabios ovmf) ],
589 description
=> "Select BIOS implementation.",
590 default => 'seabios',
594 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
595 format_description
=> 'UUID',
596 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
597 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
598 " 128-bit integer value identifier to the guest OS. This allows to".
599 " notify the guest operating system when the virtual machine is".
600 " executed with a different configuration (e.g. snapshot execution".
601 " or creation from a template). The guest operating system notices".
602 " the change, and is then able to react as appropriate by marking".
603 " its copies of distributed databases as dirty, re-initializing its".
604 " random number generator, etc.\n".
605 "Note that auto-creation only works when done throug API/CLI create".
606 " or update methods, but not when manually editing the config file.",
607 default => "1 (autogenerated)",
612 my $confdesc_cloudinit = {
616 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.',
617 enum
=> ['configdrive2', 'nocloud'],
622 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
627 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.',
632 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.",
636 type
=> 'string', format
=> 'address-list',
637 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.",
642 format
=> 'urlencoded',
643 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
647 # what about other qemu settings ?
649 #machine => 'string',
662 ##soundhw => 'string',
664 while (my ($k, $v) = each %$confdesc) {
665 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
668 my $MAX_IDE_DISKS = 4;
669 my $MAX_SCSI_DISKS = 14;
670 my $MAX_VIRTIO_DISKS = 16;
671 my $MAX_SATA_DISKS = 6;
672 my $MAX_USB_DEVICES = 5;
674 my $MAX_UNUSED_DISKS = 256;
675 my $MAX_HOSTPCI_DEVICES = 4;
676 my $MAX_SERIAL_PORTS = 4;
677 my $MAX_PARALLEL_PORTS = 3;
683 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
684 description
=> "CPUs accessing this NUMA node.",
685 format_description
=> "id[-id];...",
689 description
=> "Amount of memory this NUMA node provides.",
694 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
695 description
=> "Host NUMA nodes to use.",
696 format_description
=> "id[-id];...",
701 enum
=> [qw(preferred bind interleave)],
702 description
=> "NUMA allocation policy.",
706 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
709 type
=> 'string', format
=> $numa_fmt,
710 description
=> "NUMA topology.",
712 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
714 for (my $i = 0; $i < $MAX_NUMA; $i++) {
715 $confdesc->{"numa$i"} = $numadesc;
718 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
719 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
720 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
721 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
723 my $net_fmt_bridge_descr = <<__EOD__;
724 Bridge to attach the network device to. The Proxmox VE standard bridge
727 If you do not specify a bridge, we create a kvm user (NATed) network
728 device, which provides DHCP and DNS services. The following addresses
735 The DHCP server assign addresses to the guest starting from 10.0.2.15.
741 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
742 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
743 format_description
=> "XX:XX:XX:XX:XX:XX",
748 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'.",
749 enum
=> $nic_model_list,
752 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
755 description
=> $net_fmt_bridge_descr,
756 format_description
=> 'bridge',
761 minimum
=> 0, maximum
=> 16,
762 description
=> 'Number of packet queues to be used on the device.',
768 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
773 minimum
=> 1, maximum
=> 4094,
774 description
=> 'VLAN tag to apply to packets on this interface.',
779 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
780 description
=> 'VLAN trunks to pass through this interface.',
781 format_description
=> 'vlanid[;vlanid...]',
786 description
=> 'Whether this interface should be protected by the firewall.',
791 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
798 type
=> 'string', format
=> $net_fmt,
799 description
=> "Specify network devices.",
802 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
807 format
=> 'pve-ipv4-config',
808 format_description
=> 'IPv4Format/CIDR',
809 description
=> 'IPv4 address in CIDR format.',
816 format_description
=> 'GatewayIPv4',
817 description
=> 'Default gateway for IPv4 traffic.',
823 format
=> 'pve-ipv6-config',
824 format_description
=> 'IPv6Format/CIDR',
825 description
=> 'IPv6 address in CIDR format.',
832 format_description
=> 'GatewayIPv6',
833 description
=> 'Default gateway for IPv6 traffic.',
838 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
841 type
=> 'string', format
=> 'pve-qm-ipconfig',
842 description
=> <<'EODESCR',
843 cloud-init: Specify IP addresses and gateways for the corresponding interface.
845 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
847 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
848 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
850 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
853 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
855 for (my $i = 0; $i < $MAX_NETS; $i++) {
856 $confdesc->{"net$i"} = $netdesc;
857 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
860 foreach my $key (keys %$confdesc_cloudinit) {
861 $confdesc->{$key} = $confdesc_cloudinit->{$key};
864 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
865 sub verify_volume_id_or_qm_path
{
866 my ($volid, $noerr) = @_;
868 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
872 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
873 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
875 return undef if $noerr;
883 my %drivedesc_base = (
884 volume
=> { alias
=> 'file' },
887 format
=> 'pve-volume-id-or-qm-path',
889 format_description
=> 'volume',
890 description
=> "The drive's backing volume.",
894 enum
=> [qw(cdrom disk)],
895 description
=> "The drive's media type.",
901 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
906 description
=> "Force the drive's physical geometry to have a specific head count.",
911 description
=> "Force the drive's physical geometry to have a specific sector count.",
916 enum
=> [qw(none lba auto)],
917 description
=> "Force disk geometry bios translation mode.",
922 description
=> "Controls qemu's snapshot mode feature."
923 . " If activated, changes made to the disk are temporary and will"
924 . " be discarded when the VM is shutdown.",
929 enum
=> [qw(none writethrough writeback unsafe directsync)],
930 description
=> "The drive's cache mode",
933 format
=> get_standard_option
('pve-qm-image-format'),
936 format
=> 'disk-size',
937 format_description
=> 'DiskSize',
938 description
=> "Disk size. This is purely informational and has no effect.",
943 description
=> "Whether the drive should be included when making backups.",
948 description
=> 'Whether the drive should considered for replication jobs.',
954 enum
=> [qw(ignore report stop)],
955 description
=> 'Read error action.',
960 enum
=> [qw(enospc ignore report stop)],
961 description
=> 'Write error action.',
966 enum
=> [qw(native threads)],
967 description
=> 'AIO type to use.',
972 enum
=> [qw(ignore on)],
973 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
978 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
983 format
=> 'urlencoded',
984 format_description
=> 'serial',
985 maxLength
=> 20*3, # *3 since it's %xx url enoded
986 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
991 description
=> 'Mark this locally-managed volume as available on all nodes',
992 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!",
998 my %iothread_fmt = ( iothread
=> {
1000 description
=> "Whether to use iothreads for this drive",
1007 format
=> 'urlencoded',
1008 format_description
=> 'model',
1009 maxLength
=> 40*3, # *3 since it's %xx url enoded
1010 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1018 description
=> "Number of queues.",
1024 my %scsiblock_fmt = (
1027 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",
1036 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1041 my $add_throttle_desc = sub {
1042 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1045 format_description
=> $unit,
1046 description
=> "Maximum $what in $longunit.",
1049 $d->{minimum
} = $minimum if defined($minimum);
1050 $drivedesc_base{$key} = $d;
1052 # throughput: (leaky bucket)
1053 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1054 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1055 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1056 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1057 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1058 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1059 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1060 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1061 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1063 # pools: (pool of IO before throttling starts taking effect)
1064 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1065 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1066 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1067 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1068 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1069 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1072 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1073 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1074 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1075 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1076 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1077 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1080 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1081 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1082 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1083 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1090 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1094 type
=> 'string', format
=> $ide_fmt,
1095 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1097 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1108 type
=> 'string', format
=> $scsi_fmt,
1109 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1111 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1119 type
=> 'string', format
=> $sata_fmt,
1120 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1122 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1130 type
=> 'string', format
=> $virtio_fmt,
1131 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1133 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1135 my $alldrive_fmt = {
1145 volume
=> { alias
=> 'file' },
1148 format
=> 'pve-volume-id-or-qm-path',
1150 format_description
=> 'volume',
1151 description
=> "The drive's backing volume.",
1153 format
=> get_standard_option
('pve-qm-image-format'),
1156 format
=> 'disk-size',
1157 format_description
=> 'DiskSize',
1158 description
=> "Disk size. This is purely informational and has no effect.",
1163 my $efidisk_desc = {
1165 type
=> 'string', format
=> $efidisk_fmt,
1166 description
=> "Configure a Disk for storing EFI vars",
1169 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1174 type
=> 'string', format
=> 'pve-qm-usb-device',
1175 format_description
=> 'HOSTUSBDEVICE|spice',
1176 description
=> <<EODESCR,
1177 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1179 'bus-port(.port)*' (decimal numbers) or
1180 'vendor_id:product_id' (hexadeciaml numbers) or
1183 You can use the 'lsusb -t' command to list existing usb devices.
1185 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1187 The value 'spice' can be used to add a usb redirection devices for spice.
1193 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).",
1200 type
=> 'string', format
=> $usb_fmt,
1201 description
=> "Configure an USB device (n is 0 to 4).",
1203 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1205 # NOTE: the match-groups of this regex are used in parse_hostpci
1206 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1211 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1212 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1213 description
=> <<EODESCR,
1214 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1215 of PCI virtual functions of the host. HOSTPCIID syntax is:
1217 'bus:dev.func' (hexadecimal numbers)
1219 You can us the 'lspci' command to list existing PCI devices.
1224 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1230 pattern
=> '[^,;]+',
1231 format_description
=> 'string',
1232 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1237 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1243 description
=> "Enable vfio-vga device support.",
1248 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1252 type
=> 'string', format
=> 'pve-qm-hostpci',
1253 description
=> "Map host PCI devices into guest.",
1254 verbose_description
=> <<EODESCR,
1255 Map host PCI devices into guest.
1257 NOTE: This option allows direct access to host hardware. So it is no longer
1258 possible to migrate such machines - use with special care.
1260 CAUTION: Experimental! User reported problems with this option.
1263 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1268 pattern
=> '(/dev/.+|socket)',
1269 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1270 verbose_description
=> <<EODESCR,
1271 Create a serial device inside the VM (n is 0 to 3), and pass through a
1272 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1273 host side (use 'qm terminal' to open a terminal connection).
1275 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1277 CAUTION: Experimental! User reported problems with this option.
1284 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1285 description
=> "Map host parallel devices (n is 0 to 2).",
1286 verbose_description
=> <<EODESCR,
1287 Map host parallel devices (n is 0 to 2).
1289 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1291 CAUTION: Experimental! User reported problems with this option.
1295 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1296 $confdesc->{"parallel$i"} = $paralleldesc;
1299 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1300 $confdesc->{"serial$i"} = $serialdesc;
1303 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1304 $confdesc->{"hostpci$i"} = $hostpcidesc;
1307 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1308 $drivename_hash->{"ide$i"} = 1;
1309 $confdesc->{"ide$i"} = $idedesc;
1312 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1313 $drivename_hash->{"sata$i"} = 1;
1314 $confdesc->{"sata$i"} = $satadesc;
1317 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1318 $drivename_hash->{"scsi$i"} = 1;
1319 $confdesc->{"scsi$i"} = $scsidesc ;
1322 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1323 $drivename_hash->{"virtio$i"} = 1;
1324 $confdesc->{"virtio$i"} = $virtiodesc;
1327 $drivename_hash->{efidisk0
} = 1;
1328 $confdesc->{efidisk0
} = $efidisk_desc;
1330 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1331 $confdesc->{"usb$i"} = $usbdesc;
1336 type
=> 'string', format
=> 'pve-volume-id',
1337 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1340 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1341 $confdesc->{"unused$i"} = $unuseddesc;
1344 my $kvm_api_version = 0;
1347 return $kvm_api_version if $kvm_api_version;
1349 open my $fh, '<', '/dev/kvm'
1352 # 0xae00 => KVM_GET_API_VERSION
1353 $kvm_api_version = ioctl($fh, 0xae00, 0);
1355 return $kvm_api_version;
1358 my $kvm_user_version;
1360 sub kvm_user_version
{
1362 return $kvm_user_version if $kvm_user_version;
1364 $kvm_user_version = 'unknown';
1368 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1369 $kvm_user_version = $2;
1373 eval { run_command
("kvm -version", outfunc
=> $code); };
1376 return $kvm_user_version;
1380 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1382 sub valid_drive_names
{
1383 # order is important - used to autoselect boot disk
1384 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1385 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1386 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1387 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1391 sub is_valid_drivename
{
1394 return defined($drivename_hash->{$dev});
1399 return defined($confdesc->{$key});
1403 return $nic_model_list;
1406 sub os_list_description
{
1410 wxp
=> 'Windows XP',
1411 w2k
=> 'Windows 2000',
1412 w2k3
=>, 'Windows 2003',
1413 w2k8
=> 'Windows 2008',
1414 wvista
=> 'Windows Vista',
1415 win7
=> 'Windows 7',
1416 win8
=> 'Windows 8/2012',
1417 win10
=> 'Windows 10/2016',
1425 sub get_cdrom_path
{
1427 return $cdrom_path if $cdrom_path;
1429 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1430 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1431 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1435 my ($storecfg, $vmid, $cdrom) = @_;
1437 if ($cdrom eq 'cdrom') {
1438 return get_cdrom_path
();
1439 } elsif ($cdrom eq 'none') {
1441 } elsif ($cdrom =~ m
|^/|) {
1444 return PVE
::Storage
::path
($storecfg, $cdrom);
1448 # try to convert old style file names to volume IDs
1449 sub filename_to_volume_id
{
1450 my ($vmid, $file, $media) = @_;
1452 if (!($file eq 'none' || $file eq 'cdrom' ||
1453 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1455 return undef if $file =~ m
|/|;
1457 if ($media && $media eq 'cdrom') {
1458 $file = "local:iso/$file";
1460 $file = "local:$vmid/$file";
1467 sub verify_media_type
{
1468 my ($opt, $vtype, $media) = @_;
1473 if ($media eq 'disk') {
1475 } elsif ($media eq 'cdrom') {
1478 die "internal error";
1481 return if ($vtype eq $etype);
1483 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1486 sub cleanup_drive_path
{
1487 my ($opt, $storecfg, $drive) = @_;
1489 # try to convert filesystem paths to volume IDs
1491 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1492 ($drive->{file
} !~ m
|^/dev/.+|) &&
1493 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1494 ($drive->{file
} !~ m/^\d+$/)) {
1495 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1496 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1497 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1498 verify_media_type
($opt, $vtype, $drive->{media
});
1499 $drive->{file
} = $volid;
1502 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1505 sub parse_hotplug_features
{
1510 return $res if $data eq '0';
1512 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1514 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1515 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1518 die "invalid hotplug feature '$feature'\n";
1524 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1525 sub pve_verify_hotplug_features
{
1526 my ($value, $noerr) = @_;
1528 return $value if parse_hotplug_features
($value);
1530 return undef if $noerr;
1532 die "unable to parse hotplug option\n";
1535 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1536 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1537 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1538 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1539 # [,iothread=on][,serial=serial][,model=model]
1542 my ($key, $data) = @_;
1544 my ($interface, $index);
1546 if ($key =~ m/^([^\d]+)(\d+)$/) {
1553 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1554 : $confdesc->{$key}->{format
};
1556 warn "invalid drive key: $key\n";
1559 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1560 return undef if !$res;
1561 $res->{interface
} = $interface;
1562 $res->{index} = $index;
1565 foreach my $opt (qw(bps bps_rd bps_wr)) {
1566 if (my $bps = defined(delete $res->{$opt})) {
1567 if (defined($res->{"m$opt"})) {
1568 warn "both $opt and m$opt specified\n";
1572 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1576 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1577 for my $requirement (
1578 [mbps_max
=> 'mbps'],
1579 [mbps_rd_max
=> 'mbps_rd'],
1580 [mbps_wr_max
=> 'mbps_wr'],
1581 [miops_max
=> 'miops'],
1582 [miops_rd_max
=> 'miops_rd'],
1583 [miops_wr_max
=> 'miops_wr'],
1584 [bps_max_length
=> 'mbps_max'],
1585 [bps_rd_max_length
=> 'mbps_rd_max'],
1586 [bps_wr_max_length
=> 'mbps_wr_max'],
1587 [iops_max_length
=> 'iops_max'],
1588 [iops_rd_max_length
=> 'iops_rd_max'],
1589 [iops_wr_max_length
=> 'iops_wr_max']) {
1590 my ($option, $requires) = @$requirement;
1591 if ($res->{$option} && !$res->{$requires}) {
1592 warn "$option requires $requires\n";
1597 return undef if $error;
1599 return undef if $res->{mbps_rd
} && $res->{mbps
};
1600 return undef if $res->{mbps_wr
} && $res->{mbps
};
1601 return undef if $res->{iops_rd
} && $res->{iops
};
1602 return undef if $res->{iops_wr
} && $res->{iops
};
1604 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1605 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1606 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1607 return undef if $res->{interface
} eq 'virtio';
1610 if (my $size = $res->{size
}) {
1611 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1618 my ($vmid, $drive) = @_;
1619 my $data = { %$drive };
1620 delete $data->{$_} for qw(index interface);
1621 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1625 my($fh, $noerr) = @_;
1628 my $SG_GET_VERSION_NUM = 0x2282;
1630 my $versionbuf = "\x00" x
8;
1631 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1633 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1636 my $version = unpack("I", $versionbuf);
1637 if ($version < 30000) {
1638 die "scsi generic interface too old\n" if !$noerr;
1642 my $buf = "\x00" x
36;
1643 my $sensebuf = "\x00" x
8;
1644 my $cmd = pack("C x3 C x1", 0x12, 36);
1646 # see /usr/include/scsi/sg.h
1647 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";
1649 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1650 length($sensebuf), 0, length($buf), $buf,
1651 $cmd, $sensebuf, 6000);
1653 $ret = ioctl($fh, $SG_IO, $packet);
1655 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1659 my @res = unpack($sg_io_hdr_t, $packet);
1660 if ($res[17] || $res[18]) {
1661 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1666 (my $byte0, my $byte1, $res->{vendor
},
1667 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1669 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1670 $res->{type
} = $byte0 & 31;
1678 my $fh = IO
::File-
>new("+<$path") || return undef;
1679 my $res = scsi_inquiry
($fh, 1);
1685 sub machine_type_is_q35
{
1688 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1691 sub print_tabletdevice_full
{
1692 my ($conf, $arch) = @_;
1694 my $q35 = machine_type_is_q35
($conf);
1696 # we use uhci for old VMs because tablet driver was buggy in older qemu
1698 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1704 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1707 sub print_keyboarddevice_full
{
1708 my ($conf, $arch, $machine) = @_;
1710 return undef if $arch ne 'aarch64';
1712 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1715 sub print_drivedevice_full
{
1716 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1721 if ($drive->{interface
} eq 'virtio') {
1722 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1723 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1724 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1725 } elsif ($drive->{interface
} eq 'scsi') {
1727 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1728 my $unit = $drive->{index} % $maxdev;
1729 my $devicetype = 'hd';
1731 if (drive_is_cdrom
($drive)) {
1734 if ($drive->{file
} =~ m
|^/|) {
1735 $path = $drive->{file
};
1736 if (my $info = path_is_scsi
($path)) {
1737 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1738 $devicetype = 'block';
1739 } elsif ($info->{type
} == 1) { # tape
1740 $devicetype = 'generic';
1744 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1747 if($path =~ m/^iscsi\:\/\
//){
1748 $devicetype = 'generic';
1752 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1753 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1755 $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}";
1758 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1759 $device .= ",rotation_rate=1";
1762 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1763 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1764 my $controller = int($drive->{index} / $maxdev);
1765 my $unit = $drive->{index} % $maxdev;
1766 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1768 $device = "ide-$devicetype";
1769 if ($drive->{interface
} eq 'ide') {
1770 $device .= ",bus=ide.$controller,unit=$unit";
1772 $device .= ",bus=ahci$controller.$unit";
1774 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1776 if ($devicetype eq 'hd') {
1777 if (my $model = $drive->{model
}) {
1778 $model = URI
::Escape
::uri_unescape
($model);
1779 $device .= ",model=$model";
1781 if ($drive->{ssd
}) {
1782 $device .= ",rotation_rate=1";
1785 } elsif ($drive->{interface
} eq 'usb') {
1787 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1789 die "unsupported interface type";
1792 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1794 if (my $serial = $drive->{serial
}) {
1795 $serial = URI
::Escape
::uri_unescape
($serial);
1796 $device .= ",serial=$serial";
1803 sub get_initiator_name
{
1806 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1807 while (defined(my $line = <$fh>)) {
1808 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1817 sub print_drive_full
{
1818 my ($storecfg, $vmid, $drive) = @_;
1821 my $volid = $drive->{file
};
1824 if (drive_is_cdrom
($drive)) {
1825 $path = get_iso_path
($storecfg, $vmid, $volid);
1827 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1829 $path = PVE
::Storage
::path
($storecfg, $volid);
1830 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1831 $format = qemu_img_format
($scfg, $volname);
1839 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1840 foreach my $o (@qemu_drive_options) {
1841 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1844 # snapshot only accepts on|off
1845 if (defined($drive->{snapshot
})) {
1846 my $v = $drive->{snapshot
} ?
'on' : 'off';
1847 $opts .= ",snapshot=$v";
1850 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1851 my ($dir, $qmpname) = @$type;
1852 if (my $v = $drive->{"mbps$dir"}) {
1853 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1855 if (my $v = $drive->{"mbps${dir}_max"}) {
1856 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1858 if (my $v = $drive->{"bps${dir}_max_length"}) {
1859 $opts .= ",throttling.bps$qmpname-max-length=$v";
1861 if (my $v = $drive->{"iops${dir}"}) {
1862 $opts .= ",throttling.iops$qmpname=$v";
1864 if (my $v = $drive->{"iops${dir}_max"}) {
1865 $opts .= ",throttling.iops$qmpname-max=$v";
1867 if (my $v = $drive->{"iops${dir}_max_length"}) {
1868 $opts .= ",throttling.iops$qmpname-max-length=$v";
1872 $opts .= ",format=$format" if $format && !$drive->{format
};
1874 my $cache_direct = 0;
1876 if (my $cache = $drive->{cache
}) {
1877 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1878 } elsif (!drive_is_cdrom
($drive)) {
1879 $opts .= ",cache=none";
1883 # aio native works only with O_DIRECT
1884 if (!$drive->{aio
}) {
1886 $opts .= ",aio=native";
1888 $opts .= ",aio=threads";
1892 if (!drive_is_cdrom
($drive)) {
1894 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1895 $detectzeroes = 'off';
1896 } elsif ($drive->{discard
}) {
1897 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1899 # This used to be our default with discard not being specified:
1900 $detectzeroes = 'on';
1902 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1905 my $pathinfo = $path ?
"file=$path," : '';
1907 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1910 sub print_netdevice_full
{
1911 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1913 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1915 my $device = $net->{model
};
1916 if ($net->{model
} eq 'virtio') {
1917 $device = 'virtio-net-pci';
1920 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1921 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1922 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1923 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1924 my $vectors = $net->{queues
} * 2 + 2;
1925 $tmpstr .= ",vectors=$vectors,mq=on";
1927 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1929 if ($use_old_bios_files) {
1931 if ($device eq 'virtio-net-pci') {
1932 $romfile = 'pxe-virtio.rom';
1933 } elsif ($device eq 'e1000') {
1934 $romfile = 'pxe-e1000.rom';
1935 } elsif ($device eq 'ne2k') {
1936 $romfile = 'pxe-ne2k_pci.rom';
1937 } elsif ($device eq 'pcnet') {
1938 $romfile = 'pxe-pcnet.rom';
1939 } elsif ($device eq 'rtl8139') {
1940 $romfile = 'pxe-rtl8139.rom';
1942 $tmpstr .= ",romfile=$romfile" if $romfile;
1948 sub print_netdev_full
{
1949 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1952 if ($netid =~ m/^net(\d+)$/) {
1956 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1958 my $ifname = "tap${vmid}i$i";
1960 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1961 die "interface name '$ifname' is too long (max 15 character)\n"
1962 if length($ifname) >= 16;
1964 my $vhostparam = '';
1965 if (is_native
($arch)) {
1966 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1969 my $vmname = $conf->{name
} || "vm$vmid";
1972 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1974 if ($net->{bridge
}) {
1975 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1977 $netdev = "type=user,id=$netid,hostname=$vmname";
1980 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1986 sub print_cpu_device
{
1987 my ($conf, $id) = @_;
1989 my $kvm = $conf->{kvm
} // 1;
1990 my $cpu = $kvm ?
"kvm64" : "qemu64";
1991 if (my $cputype = $conf->{cpu
}) {
1992 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1993 or die "Cannot parse cpu description: $cputype\n";
1994 $cpu = $cpuconf->{cputype
};
1997 my $cores = $conf->{cores
} || 1;
1999 my $current_core = ($id - 1) % $cores;
2000 my $current_socket = int(($id - 1 - $current_core)/$cores);
2002 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2006 'cirrus' => 'cirrus-vga',
2008 'vmware' => 'vmware-svga',
2009 'virtio' => 'virtio-vga',
2012 sub print_vga_device
{
2013 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2015 my $type = $vga_map->{$vga->{type
}};
2016 if ($type eq 'virtio-vga' && $arch eq 'aarch64') {
2017 $type = 'virtio-gpu';
2019 my $vgamem_mb = $vga->{memory
};
2021 $type = $id ?
'qxl' : 'qxl-vga';
2023 die "no devicetype for $vga->{type}\n" if !$type;
2027 if ($vga->{type
} eq 'virtio') {
2028 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2029 $memory = ",max_hostmem=$bytes";
2031 # from https://www.spice-space.org/multiple-monitors.html
2032 $memory = ",vgamem_mb=$vga->{memory}";
2033 my $ram = $vgamem_mb * 4;
2034 my $vram = $vgamem_mb * 2;
2035 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2037 $memory = ",vgamem_mb=$vga->{memory}";
2039 } elsif ($qxlnum && $id) {
2040 $memory = ",ram_size=67108864,vram_size=33554432";
2043 my $q35 = machine_type_is_q35
($conf);
2044 my $vgaid = "vga" . ($id // '');
2047 if ($q35 && $vgaid eq 'vga') {
2048 # the first display uses pcie.0 bus on q35 machines
2049 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2051 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2054 return "$type,id=${vgaid}${memory}${pciaddr}";
2057 sub drive_is_cloudinit
{
2059 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2062 sub drive_is_cdrom
{
2063 my ($drive, $exclude_cloudinit) = @_;
2065 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2067 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2071 sub parse_number_sets
{
2074 foreach my $part (split(/;/, $set)) {
2075 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2076 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2077 push @$res, [ $1, $2 ];
2079 die "invalid range: $part\n";
2088 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2089 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2090 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2097 return undef if !$value;
2099 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2101 my @idlist = split(/;/, $res->{host
});
2102 delete $res->{host
};
2103 foreach my $id (@idlist) {
2104 if ($id =~ /^$PCIRE$/) {
2106 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
2108 my $pcidevices = PVE
::SysFSTools
::lspci
($1);
2109 $res->{pciid
} = $pcidevices->{$1};
2112 # should have been caught by parse_property_string already
2113 die "failed to parse PCI id: $id\n";
2119 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2123 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2128 if (!defined($res->{macaddr
})) {
2129 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2130 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2135 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2136 sub parse_ipconfig
{
2139 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2145 if ($res->{gw
} && !$res->{ip
}) {
2146 warn 'gateway specified without specifying an IP address';
2149 if ($res->{gw6
} && !$res->{ip6
}) {
2150 warn 'IPv6 gateway specified without specifying an IPv6 address';
2153 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2154 warn 'gateway specified together with DHCP';
2157 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2159 warn "IPv6 gateway specified together with $res->{ip6} address";
2163 if (!$res->{ip
} && !$res->{ip6
}) {
2164 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2173 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2176 sub add_random_macs
{
2177 my ($settings) = @_;
2179 foreach my $opt (keys %$settings) {
2180 next if $opt !~ m/^net(\d+)$/;
2181 my $net = parse_net
($settings->{$opt});
2183 $settings->{$opt} = print_net
($net);
2187 sub vm_is_volid_owner
{
2188 my ($storecfg, $vmid, $volid) = @_;
2190 if ($volid !~ m
|^/|) {
2192 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2193 if ($owner && ($owner == $vmid)) {
2201 sub split_flagged_list
{
2202 my $text = shift || '';
2203 $text =~ s/[,;]/ /g;
2205 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2208 sub join_flagged_list
{
2209 my ($how, $lst) = @_;
2210 join $how, map { $lst->{$_} . $_ } keys %$lst;
2213 sub vmconfig_delete_pending_option
{
2214 my ($conf, $key, $force) = @_;
2216 delete $conf->{pending
}->{$key};
2217 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2218 $pending_delete_hash->{$key} = $force ?
'!' : '';
2219 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2222 sub vmconfig_undelete_pending_option
{
2223 my ($conf, $key) = @_;
2225 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2226 delete $pending_delete_hash->{$key};
2228 if (%$pending_delete_hash) {
2229 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2231 delete $conf->{pending
}->{delete};
2235 sub vmconfig_register_unused_drive
{
2236 my ($storecfg, $vmid, $conf, $drive) = @_;
2238 if (drive_is_cloudinit
($drive)) {
2239 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2241 } elsif (!drive_is_cdrom
($drive)) {
2242 my $volid = $drive->{file
};
2243 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2244 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2249 sub vmconfig_cleanup_pending
{
2252 # remove pending changes when nothing changed
2254 foreach my $opt (keys %{$conf->{pending
}}) {
2255 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2257 delete $conf->{pending
}->{$opt};
2261 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2262 my $pending_delete_hash = {};
2263 while (my ($opt, $force) = each %$current_delete_hash) {
2264 if (defined($conf->{$opt})) {
2265 $pending_delete_hash->{$opt} = $force;
2271 if (%$pending_delete_hash) {
2272 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2274 delete $conf->{pending
}->{delete};
2280 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2284 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2285 format_description
=> 'UUID',
2286 description
=> "Set SMBIOS1 UUID.",
2292 format_description
=> 'string',
2293 description
=> "Set SMBIOS1 version.",
2299 format_description
=> 'string',
2300 description
=> "Set SMBIOS1 serial number.",
2306 format_description
=> 'string',
2307 description
=> "Set SMBIOS1 manufacturer.",
2313 format_description
=> 'string',
2314 description
=> "Set SMBIOS1 product ID.",
2320 format_description
=> 'string',
2321 description
=> "Set SMBIOS1 SKU string.",
2327 format_description
=> 'string',
2328 description
=> "Set SMBIOS1 family string.",
2336 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2343 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2346 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2348 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2349 sub verify_bootdisk
{
2350 my ($value, $noerr) = @_;
2352 return $value if is_valid_drivename
($value);
2354 return undef if $noerr;
2356 die "invalid boot disk '$value'\n";
2359 sub parse_watchdog
{
2362 return undef if !$value;
2364 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2369 sub parse_guest_agent
{
2372 return {} if !defined($value->{agent
});
2374 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2377 # if the agent is disabled ignore the other potentially set properties
2378 return {} if !$res->{enabled
};
2385 return {} if !$value;
2386 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2391 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2392 sub verify_usb_device
{
2393 my ($value, $noerr) = @_;
2395 return $value if parse_usb_device
($value);
2397 return undef if $noerr;
2399 die "unable to parse usb device\n";
2402 # add JSON properties for create and set function
2403 sub json_config_properties
{
2406 foreach my $opt (keys %$confdesc) {
2407 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2408 $prop->{$opt} = $confdesc->{$opt};
2414 # return copy of $confdesc_cloudinit to generate documentation
2415 sub cloudinit_config_properties
{
2417 return dclone
($confdesc_cloudinit);
2421 my ($key, $value) = @_;
2423 die "unknown setting '$key'\n" if !$confdesc->{$key};
2425 my $type = $confdesc->{$key}->{type
};
2427 if (!defined($value)) {
2428 die "got undefined value\n";
2431 if ($value =~ m/[\n\r]/) {
2432 die "property contains a line feed\n";
2435 if ($type eq 'boolean') {
2436 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2437 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2438 die "type check ('boolean') failed - got '$value'\n";
2439 } elsif ($type eq 'integer') {
2440 return int($1) if $value =~ m/^(\d+)$/;
2441 die "type check ('integer') failed - got '$value'\n";
2442 } elsif ($type eq 'number') {
2443 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2444 die "type check ('number') failed - got '$value'\n";
2445 } elsif ($type eq 'string') {
2446 if (my $fmt = $confdesc->{$key}->{format
}) {
2447 PVE
::JSONSchema
::check_format
($fmt, $value);
2450 $value =~ s/^\"(.*)\"$/$1/;
2453 die "internal error"
2460 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2461 utime undef, undef, $conf;
2465 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2467 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2469 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2471 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2473 if ($conf->{template
}) {
2474 # check if any base image is still used by a linked clone
2475 foreach_drive
($conf, sub {
2476 my ($ds, $drive) = @_;
2478 return if drive_is_cdrom
($drive);
2480 my $volid = $drive->{file
};
2482 return if !$volid || $volid =~ m
|^/|;
2484 die "base volume '$volid' is still in use by linked cloned\n"
2485 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2490 # only remove disks owned by this VM
2491 foreach_drive
($conf, sub {
2492 my ($ds, $drive) = @_;
2494 return if drive_is_cdrom
($drive, 1);
2496 my $volid = $drive->{file
};
2498 return if !$volid || $volid =~ m
|^/|;
2500 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2501 return if !$path || !$owner || ($owner != $vmid);
2504 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2506 warn "Could not remove disk '$volid', check manually: $@" if $@;
2510 if ($keep_empty_config) {
2511 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2516 # also remove unused disk
2518 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2521 PVE
::Storage
::foreach_volid
($dl, sub {
2522 my ($volid, $sid, $volname, $d) = @_;
2523 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2532 sub parse_vm_config
{
2533 my ($filename, $raw) = @_;
2535 return undef if !defined($raw);
2538 digest
=> Digest
::SHA
::sha1_hex
($raw),
2543 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2544 || die "got strange filename '$filename'";
2552 my @lines = split(/\n/, $raw);
2553 foreach my $line (@lines) {
2554 next if $line =~ m/^\s*$/;
2556 if ($line =~ m/^\[PENDING\]\s*$/i) {
2557 $section = 'pending';
2558 if (defined($descr)) {
2560 $conf->{description
} = $descr;
2563 $conf = $res->{$section} = {};
2566 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2568 if (defined($descr)) {
2570 $conf->{description
} = $descr;
2573 $conf = $res->{snapshots
}->{$section} = {};
2577 if ($line =~ m/^\#(.*)\s*$/) {
2578 $descr = '' if !defined($descr);
2579 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2583 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2584 $descr = '' if !defined($descr);
2585 $descr .= PVE
::Tools
::decode_text
($2);
2586 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2587 $conf->{snapstate
} = $1;
2588 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2591 $conf->{$key} = $value;
2592 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2594 if ($section eq 'pending') {
2595 $conf->{delete} = $value; # we parse this later
2597 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2599 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2602 eval { $value = check_type
($key, $value); };
2604 warn "vm $vmid - unable to parse value of '$key' - $@";
2606 $key = 'ide2' if $key eq 'cdrom';
2607 my $fmt = $confdesc->{$key}->{format
};
2608 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2609 my $v = parse_drive
($key, $value);
2610 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2611 $v->{file
} = $volid;
2612 $value = print_drive
($vmid, $v);
2614 warn "vm $vmid - unable to parse value of '$key'\n";
2619 $conf->{$key} = $value;
2624 if (defined($descr)) {
2626 $conf->{description
} = $descr;
2628 delete $res->{snapstate
}; # just to be sure
2633 sub write_vm_config
{
2634 my ($filename, $conf) = @_;
2636 delete $conf->{snapstate
}; # just to be sure
2638 if ($conf->{cdrom
}) {
2639 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2640 $conf->{ide2
} = $conf->{cdrom
};
2641 delete $conf->{cdrom
};
2644 # we do not use 'smp' any longer
2645 if ($conf->{sockets
}) {
2646 delete $conf->{smp
};
2647 } elsif ($conf->{smp
}) {
2648 $conf->{sockets
} = $conf->{smp
};
2649 delete $conf->{cores
};
2650 delete $conf->{smp
};
2653 my $used_volids = {};
2655 my $cleanup_config = sub {
2656 my ($cref, $pending, $snapname) = @_;
2658 foreach my $key (keys %$cref) {
2659 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2660 $key eq 'snapstate' || $key eq 'pending';
2661 my $value = $cref->{$key};
2662 if ($key eq 'delete') {
2663 die "propertry 'delete' is only allowed in [PENDING]\n"
2665 # fixme: check syntax?
2668 eval { $value = check_type
($key, $value); };
2669 die "unable to parse value of '$key' - $@" if $@;
2671 $cref->{$key} = $value;
2673 if (!$snapname && is_valid_drivename
($key)) {
2674 my $drive = parse_drive
($key, $value);
2675 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2680 &$cleanup_config($conf);
2682 &$cleanup_config($conf->{pending
}, 1);
2684 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2685 die "internal error" if $snapname eq 'pending';
2686 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2689 # remove 'unusedX' settings if we re-add a volume
2690 foreach my $key (keys %$conf) {
2691 my $value = $conf->{$key};
2692 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2693 delete $conf->{$key};
2697 my $generate_raw_config = sub {
2698 my ($conf, $pending) = @_;
2702 # add description as comment to top of file
2703 if (defined(my $descr = $conf->{description
})) {
2705 foreach my $cl (split(/\n/, $descr)) {
2706 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2709 $raw .= "#\n" if $pending;
2713 foreach my $key (sort keys %$conf) {
2714 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2715 $raw .= "$key: $conf->{$key}\n";
2720 my $raw = &$generate_raw_config($conf);
2722 if (scalar(keys %{$conf->{pending
}})){
2723 $raw .= "\n[PENDING]\n";
2724 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2727 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2728 $raw .= "\n[$snapname]\n";
2729 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2739 # we use static defaults from our JSON schema configuration
2740 foreach my $key (keys %$confdesc) {
2741 if (defined(my $default = $confdesc->{$key}->{default})) {
2742 $res->{$key} = $default;
2750 my $vmlist = PVE
::Cluster
::get_vmlist
();
2752 return $res if !$vmlist || !$vmlist->{ids
};
2753 my $ids = $vmlist->{ids
};
2755 foreach my $vmid (keys %$ids) {
2756 my $d = $ids->{$vmid};
2757 next if !$d->{node
} || $d->{node
} ne $nodename;
2758 next if !$d->{type
} || $d->{type
} ne 'qemu';
2759 $res->{$vmid}->{exists} = 1;
2764 # test if VM uses local resources (to prevent migration)
2765 sub check_local_resources
{
2766 my ($conf, $noerr) = @_;
2770 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2771 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2773 foreach my $k (keys %$conf) {
2774 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2775 # sockets are safe: they will recreated be on the target side post-migrate
2776 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2777 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2780 die "VM uses local resources\n" if $loc_res && !$noerr;
2785 # check if used storages are available on all nodes (use by migrate)
2786 sub check_storage_availability
{
2787 my ($storecfg, $conf, $node) = @_;
2789 foreach_drive
($conf, sub {
2790 my ($ds, $drive) = @_;
2792 my $volid = $drive->{file
};
2795 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2798 # check if storage is available on both nodes
2799 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2800 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2804 # list nodes where all VM images are available (used by has_feature API)
2806 my ($conf, $storecfg) = @_;
2808 my $nodelist = PVE
::Cluster
::get_nodelist
();
2809 my $nodehash = { map { $_ => 1 } @$nodelist };
2810 my $nodename = PVE
::INotify
::nodename
();
2812 foreach_drive
($conf, sub {
2813 my ($ds, $drive) = @_;
2815 my $volid = $drive->{file
};
2818 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2820 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2821 if ($scfg->{disable
}) {
2823 } elsif (my $avail = $scfg->{nodes
}) {
2824 foreach my $node (keys %$nodehash) {
2825 delete $nodehash->{$node} if !$avail->{$node};
2827 } elsif (!$scfg->{shared
}) {
2828 foreach my $node (keys %$nodehash) {
2829 delete $nodehash->{$node} if $node ne $nodename
2839 my ($pidfile, $pid) = @_;
2841 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2845 return undef if !$line;
2846 my @param = split(/\0/, $line);
2848 my $cmd = $param[0];
2849 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2851 for (my $i = 0; $i < scalar (@param); $i++) {
2854 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2855 my $p = $param[$i+1];
2856 return 1 if $p && ($p eq $pidfile);
2865 my ($vmid, $nocheck, $node) = @_;
2867 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2869 die "unable to find configuration file for VM $vmid - no such machine\n"
2870 if !$nocheck && ! -f
$filename;
2872 my $pidfile = pidfile_name
($vmid);
2874 if (my $fd = IO
::File-
>new("<$pidfile")) {
2879 my $mtime = $st->mtime;
2880 if ($mtime > time()) {
2881 warn "file '$filename' modified in future\n";
2884 if ($line =~ m/^(\d+)$/) {
2886 if (check_cmdline
($pidfile, $pid)) {
2887 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2899 my $vzlist = config_list
();
2901 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2903 while (defined(my $de = $fd->read)) {
2904 next if $de !~ m/^(\d+)\.pid$/;
2906 next if !defined($vzlist->{$vmid});
2907 if (my $pid = check_running
($vmid)) {
2908 $vzlist->{$vmid}->{pid
} = $pid;
2916 my ($storecfg, $conf) = @_;
2918 my $bootdisk = $conf->{bootdisk
};
2919 return undef if !$bootdisk;
2920 return undef if !is_valid_drivename
($bootdisk);
2922 return undef if !$conf->{$bootdisk};
2924 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2925 return undef if !defined($drive);
2927 return undef if drive_is_cdrom
($drive);
2929 my $volid = $drive->{file
};
2930 return undef if !$volid;
2932 return $drive->{size
};
2935 our $vmstatus_return_properties = {
2936 vmid
=> get_standard_option
('pve-vmid'),
2938 description
=> "Qemu process status.",
2940 enum
=> ['stopped', 'running'],
2943 description
=> "Maximum memory in bytes.",
2946 renderer
=> 'bytes',
2949 description
=> "Root disk size in bytes.",
2952 renderer
=> 'bytes',
2955 description
=> "VM name.",
2960 description
=> "Qemu QMP agent status.",
2965 description
=> "PID of running qemu process.",
2970 description
=> "Uptime.",
2973 renderer
=> 'duration',
2976 description
=> "Maximum usable CPUs.",
2982 my $last_proc_pid_stat;
2984 # get VM status information
2985 # This must be fast and should not block ($full == false)
2986 # We only query KVM using QMP if $full == true (this can be slow)
2988 my ($opt_vmid, $full) = @_;
2992 my $storecfg = PVE
::Storage
::config
();
2994 my $list = vzlist
();
2995 my $defaults = load_defaults
();
2997 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2999 my $cpucount = $cpuinfo->{cpus
} || 1;
3001 foreach my $vmid (keys %$list) {
3002 next if $opt_vmid && ($vmid ne $opt_vmid);
3004 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3005 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3007 my $d = { vmid
=> $vmid };
3008 $d->{pid
} = $list->{$vmid}->{pid
};
3010 # fixme: better status?
3011 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3013 my $size = disksize
($storecfg, $conf);
3014 if (defined($size)) {
3015 $d->{disk
} = 0; # no info available
3016 $d->{maxdisk
} = $size;
3022 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3023 * ($conf->{cores
} || $defaults->{cores
});
3024 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3025 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3027 $d->{name
} = $conf->{name
} || "VM $vmid";
3028 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3029 : $defaults->{memory
}*(1024*1024);
3031 if ($conf->{balloon
}) {
3032 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3033 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3034 : $defaults->{shares
};
3045 $d->{diskwrite
} = 0;
3047 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3049 $d->{serial
} = 1 if conf_has_serial
($conf);
3054 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3055 foreach my $dev (keys %$netdev) {
3056 next if $dev !~ m/^tap([1-9]\d*)i/;
3058 my $d = $res->{$vmid};
3061 $d->{netout
} += $netdev->{$dev}->{receive
};
3062 $d->{netin
} += $netdev->{$dev}->{transmit
};
3065 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3066 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3071 my $ctime = gettimeofday
;
3073 foreach my $vmid (keys %$list) {
3075 my $d = $res->{$vmid};
3076 my $pid = $d->{pid
};
3079 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3080 next if !$pstat; # not running
3082 my $used = $pstat->{utime} + $pstat->{stime
};
3084 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3086 if ($pstat->{vsize
}) {
3087 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3090 my $old = $last_proc_pid_stat->{$pid};
3092 $last_proc_pid_stat->{$pid} = {
3100 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3102 if ($dtime > 1000) {
3103 my $dutime = $used - $old->{used
};
3105 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3106 $last_proc_pid_stat->{$pid} = {
3112 $d->{cpu
} = $old->{cpu
};
3116 return $res if !$full;
3118 my $qmpclient = PVE
::QMPClient-
>new();
3120 my $ballooncb = sub {
3121 my ($vmid, $resp) = @_;
3123 my $info = $resp->{'return'};
3124 return if !$info->{max_mem
};
3126 my $d = $res->{$vmid};
3128 # use memory assigned to VM
3129 $d->{maxmem
} = $info->{max_mem
};
3130 $d->{balloon
} = $info->{actual
};
3132 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3133 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3134 $d->{freemem
} = $info->{free_mem
};
3137 $d->{ballooninfo
} = $info;
3140 my $blockstatscb = sub {
3141 my ($vmid, $resp) = @_;
3142 my $data = $resp->{'return'} || [];
3143 my $totalrdbytes = 0;
3144 my $totalwrbytes = 0;
3146 for my $blockstat (@$data) {
3147 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3148 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3150 $blockstat->{device
} =~ s/drive-//;
3151 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3153 $res->{$vmid}->{diskread
} = $totalrdbytes;
3154 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3157 my $statuscb = sub {
3158 my ($vmid, $resp) = @_;
3160 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3161 # this fails if ballon driver is not loaded, so this must be
3162 # the last commnand (following command are aborted if this fails).
3163 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3165 my $status = 'unknown';
3166 if (!defined($status = $resp->{'return'}->{status
})) {
3167 warn "unable to get VM status\n";
3171 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3174 foreach my $vmid (keys %$list) {
3175 next if $opt_vmid && ($vmid ne $opt_vmid);
3176 next if !$res->{$vmid}->{pid
}; # not running
3177 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3180 $qmpclient->queue_execute(undef, 2);
3182 foreach my $vmid (keys %$list) {
3183 next if $opt_vmid && ($vmid ne $opt_vmid);
3184 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3191 my ($conf, $func, @param) = @_;
3193 foreach my $ds (valid_drive_names
()) {
3194 next if !defined($conf->{$ds});
3196 my $drive = parse_drive
($ds, $conf->{$ds});
3199 &$func($ds, $drive, @param);
3204 my ($conf, $func, @param) = @_;
3208 my $test_volid = sub {
3209 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3213 $volhash->{$volid}->{cdrom
} //= 1;
3214 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3216 $volhash->{$volid}->{replicate
} //= 0;
3217 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3219 $volhash->{$volid}->{shared
} //= 0;
3220 $volhash->{$volid}->{shared
} = 1 if $shared;
3222 $volhash->{$volid}->{referenced_in_config
} //= 0;
3223 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3225 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3226 if defined($snapname);
3229 foreach_drive
($conf, sub {
3230 my ($ds, $drive) = @_;
3231 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3234 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3235 my $snap = $conf->{snapshots
}->{$snapname};
3236 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3237 foreach_drive
($snap, sub {
3238 my ($ds, $drive) = @_;
3239 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3243 foreach my $volid (keys %$volhash) {
3244 &$func($volid, $volhash->{$volid}, @param);
3248 sub conf_has_serial
{
3251 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3252 if ($conf->{"serial$i"}) {
3260 sub vga_conf_has_spice
{
3263 my $vgaconf = parse_vga
($vga);
3264 my $vgatype = $vgaconf->{type
};
3265 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3270 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3271 sub get_host_arch
() {
3272 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3278 return get_host_arch
() eq $arch;
3281 my $default_machines = {
3286 sub get_basic_machine_info
{
3287 my ($conf, $forcemachine) = @_;
3289 my $arch = $conf->{arch
} // get_host_arch
();
3290 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3291 return ($arch, $machine);
3294 sub get_ovmf_files
($) {
3297 my $ovmf = $OVMF->{$arch}
3298 or die "no OVMF images known for architecture '$arch'\n";
3304 aarch64
=> '/usr/bin/qemu-system-aarch64',
3305 x86_64
=> '/usr/bin/qemu-system-x86_64',
3307 sub get_command_for_arch
($) {
3309 return '/usr/bin/kvm' if is_native
($arch);
3311 my $cmd = $Arch2Qemu->{$arch}
3312 or die "don't know how to emulate architecture '$arch'\n";
3316 sub get_cpu_options
{
3317 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3320 my $ostype = $conf->{ostype
};
3322 my $cpu = $kvm ?
"kvm64" : "qemu64";
3323 if ($arch eq 'aarch64') {
3324 $cpu = 'cortex-a57';
3326 if (my $cputype = $conf->{cpu
}) {
3327 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3328 or die "Cannot parse cpu description: $cputype\n";
3329 $cpu = $cpuconf->{cputype
};
3330 $kvm_off = 1 if $cpuconf->{hidden
};
3332 if (defined(my $flags = $cpuconf->{flags
})) {
3333 push @$cpuFlags, split(";", $flags);
3337 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3339 push @$cpuFlags , '-x2apic'
3340 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3342 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3344 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3346 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3348 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3349 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3352 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3354 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3356 push @$cpuFlags, 'kvm=off' if $kvm_off;
3358 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3359 push @$cpuFlags, "vendor=${cpu_vendor}"
3360 if $cpu_vendor ne 'default';
3361 } elsif ($arch ne 'aarch64') {
3362 die "internal error"; # should not happen
3365 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3367 return ('-cpu', $cpu);
3370 sub config_to_command
{
3371 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3374 my $globalFlags = [];
3375 my $machineFlags = [];
3380 my $kvmver = kvm_user_version
();
3381 my $vernum = 0; # unknown
3382 my $ostype = $conf->{ostype
};
3383 my $winversion = windows_version
($ostype);
3384 my $kvm = $conf->{kvm
};
3386 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3387 $kvm //= 1 if is_native
($arch);
3390 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3391 if !defined kvm_version
();
3394 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3395 $vernum = $1*1000000+$2*1000;
3396 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3397 $vernum = $1*1000000+$2*1000+$3;
3400 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3402 my $have_ovz = -f
'/proc/vz/vestat';
3404 my $q35 = machine_type_is_q35
($conf);
3405 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3406 my $use_old_bios_files = undef;
3407 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3409 my $cpuunits = defined($conf->{cpuunits
}) ?
3410 $conf->{cpuunits
} : $defaults->{cpuunits
};
3412 push @$cmd, get_command_for_arch
($arch);
3414 push @$cmd, '-id', $vmid;
3416 my $vmname = $conf->{name
} || "vm$vmid";
3418 push @$cmd, '-name', $vmname;
3422 my $qmpsocket = qmp_socket
($vmid);
3423 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3424 push @$cmd, '-mon', "chardev=qmp,mode=control";
3426 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3427 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3428 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3431 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3433 push @$cmd, '-daemonize';
3435 if ($conf->{smbios1
}) {
3436 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3439 if ($conf->{vmgenid
}) {
3440 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3443 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3444 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3445 die "uefi base image not found\n" if ! -f
$ovmf_code;
3449 if (my $efidisk = $conf->{efidisk0
}) {
3450 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3451 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3452 $format = $d->{format
};
3454 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3455 if (!defined($format)) {
3456 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3457 $format = qemu_img_format
($scfg, $volname);
3461 die "efidisk format must be specified\n"
3462 if !defined($format);
3465 warn "no efidisk configured! Using temporary efivars disk.\n";
3466 $path = "/tmp/$vmid-ovmf.fd";
3467 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3471 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3472 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3476 # add usb controllers
3477 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3478 push @$devices, @usbcontrollers if @usbcontrollers;
3479 my $vga = parse_vga
($conf->{vga
});
3481 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3482 $vga->{type
} = 'qxl' if $qxlnum;
3484 if (!$vga->{type
}) {
3485 if ($arch eq 'aarch64') {
3486 $vga->{type
} = 'virtio';
3487 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3488 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3490 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3494 # enable absolute mouse coordinates (needed by vnc)
3496 if (defined($conf->{tablet
})) {
3497 $tablet = $conf->{tablet
};
3499 $tablet = $defaults->{tablet
};
3500 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3501 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3505 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3506 my $kbd = print_keyboarddevice_full
($conf, $arch);
3507 push @$devices, '-device', $kbd if defined($kbd);
3511 my $gpu_passthrough;
3514 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3515 my $d = parse_hostpci
($conf->{"hostpci$i"});
3518 my $pcie = $d->{pcie
};
3520 die "q35 machine model is not enabled" if !$q35;
3521 $pciaddr = print_pcie_addr
("hostpci$i");
3523 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3526 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3527 my $romfile = $d->{romfile
};
3530 if ($d->{'x-vga'}) {
3531 $xvga = ',x-vga=on';
3533 $vga->{type
} = 'none';
3534 $gpu_passthrough = 1;
3536 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3540 my $pcidevices = $d->{pciid
};
3541 my $multifunction = 1 if @$pcidevices > 1;
3544 foreach my $pcidevice (@$pcidevices) {
3546 my $id = "hostpci$i";
3547 $id .= ".$j" if $multifunction;
3548 my $addr = $pciaddr;
3549 $addr .= ".$j" if $multifunction;
3550 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3553 $devicestr .= "$rombar$xvga";
3554 $devicestr .= ",multifunction=on" if $multifunction;
3555 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3558 push @$devices, '-device', $devicestr;
3564 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3565 push @$devices, @usbdevices if @usbdevices;
3567 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3568 if (my $path = $conf->{"serial$i"}) {
3569 if ($path eq 'socket') {
3570 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3571 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3572 # On aarch64, serial0 is the UART device. Qemu only allows
3573 # connecting UART devices via the '-serial' command line, as
3574 # the device has a fixed slot on the hardware...
3575 if ($arch eq 'aarch64' && $i == 0) {
3576 push @$devices, '-serial', "chardev:serial$i";
3578 push @$devices, '-device', "isa-serial,chardev=serial$i";
3581 die "no such serial device\n" if ! -c
$path;
3582 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3583 push @$devices, '-device', "isa-serial,chardev=serial$i";
3589 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3590 if (my $path = $conf->{"parallel$i"}) {
3591 die "no such parallel device\n" if ! -c
$path;
3592 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3593 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3594 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3600 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3601 $sockets = $conf->{sockets
} if $conf->{sockets
};
3603 my $cores = $conf->{cores
} || 1;
3605 my $maxcpus = $sockets * $cores;
3607 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3609 my $allowed_vcpus = $cpuinfo->{cpus
};
3611 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3612 if ($allowed_vcpus < $maxcpus);
3614 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3616 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3617 for (my $i = 2; $i <= $vcpus; $i++) {
3618 my $cpustr = print_cpu_device
($conf,$i);
3619 push @$cmd, '-device', $cpustr;
3624 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3626 push @$cmd, '-nodefaults';
3628 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3630 my $bootindex_hash = {};
3632 foreach my $o (split(//, $bootorder)) {
3633 $bootindex_hash->{$o} = $i*100;
3637 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3639 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3641 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3643 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3644 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3645 my $socket = vnc_socket
($vmid);
3646 push @$cmd, '-vnc', "unix:$socket,x509,password";
3648 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3649 push @$cmd, '-nographic';
3653 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3655 my $useLocaltime = $conf->{localtime};
3657 if ($winversion >= 5) { # windows
3658 $useLocaltime = 1 if !defined($conf->{localtime});
3660 # use time drift fix when acpi is enabled
3661 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3662 $tdf = 1 if !defined($conf->{tdf
});
3666 if ($winversion >= 6) {
3667 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3668 push @$cmd, '-no-hpet';
3671 push @$rtcFlags, 'driftfix=slew' if $tdf;
3674 push @$machineFlags, 'accel=tcg';
3677 if ($machine_type) {
3678 push @$machineFlags, "type=${machine_type}";
3681 if ($conf->{startdate
}) {
3682 push @$rtcFlags, "base=$conf->{startdate}";
3683 } elsif ($useLocaltime) {
3684 push @$rtcFlags, 'base=localtime';
3687 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3689 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3691 push @$cmd, '-S' if $conf->{freeze
};
3693 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3696 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3697 #push @$cmd, '-soundhw', 'es1370';
3698 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3700 if (parse_guest_agent
($conf)->{enabled
}) {
3701 my $qgasocket = qmp_socket
($vmid, 1);
3702 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3703 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3704 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3705 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3713 for(my $i = 1; $i < $qxlnum; $i++){
3714 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3717 # assume other OS works like Linux
3718 my ($ram, $vram) = ("134217728", "67108864");
3719 if ($vga->{memory
}) {
3720 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3721 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3723 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3724 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3728 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3730 my $nodename = PVE
::INotify
::nodename
();
3731 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3732 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3733 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3734 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3735 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3737 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3739 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3740 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3741 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3744 # enable balloon by default, unless explicitly disabled
3745 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3746 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3747 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3750 if ($conf->{watchdog
}) {
3751 my $wdopts = parse_watchdog
($conf->{watchdog
});
3752 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3753 my $watchdog = $wdopts->{model
} || 'i6300esb';
3754 push @$devices, '-device', "$watchdog$pciaddr";
3755 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3759 my $scsicontroller = {};
3760 my $ahcicontroller = {};
3761 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3763 # Add iscsi initiator name if available
3764 if (my $initiator = get_initiator_name
()) {
3765 push @$devices, '-iscsi', "initiator-name=$initiator";
3768 foreach_drive
($conf, sub {
3769 my ($ds, $drive) = @_;
3771 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3772 push @$vollist, $drive->{file
};
3775 # ignore efidisk here, already added in bios/fw handling code above
3776 return if $drive->{interface
} eq 'efidisk';
3778 $use_virtio = 1 if $ds =~ m/^virtio/;
3780 if (drive_is_cdrom
($drive)) {
3781 if ($bootindex_hash->{d
}) {
3782 $drive->{bootindex
} = $bootindex_hash->{d
};
3783 $bootindex_hash->{d
} += 1;
3786 if ($bootindex_hash->{c
}) {
3787 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3788 $bootindex_hash->{c
} += 1;
3792 if($drive->{interface
} eq 'virtio'){
3793 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3796 if ($drive->{interface
} eq 'scsi') {
3798 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3800 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3801 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3804 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3805 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3806 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3807 } elsif ($drive->{iothread
}) {
3808 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3812 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3813 $queues = ",num_queues=$drive->{queues}";
3816 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3817 $scsicontroller->{$controller}=1;
3820 if ($drive->{interface
} eq 'sata') {
3821 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3822 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3823 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3824 $ahcicontroller->{$controller}=1;
3827 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3828 push @$devices, '-drive',$drive_cmd;
3829 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3832 for (my $i = 0; $i < $MAX_NETS; $i++) {
3833 next if !$conf->{"net$i"};
3834 my $d = parse_net
($conf->{"net$i"});
3837 $use_virtio = 1 if $d->{model
} eq 'virtio';
3839 if ($bootindex_hash->{n
}) {
3840 $d->{bootindex
} = $bootindex_hash->{n
};
3841 $bootindex_hash->{n
} += 1;
3844 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3845 push @$devices, '-netdev', $netdevfull;
3847 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3848 push @$devices, '-device', $netdevicefull;
3853 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3858 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3860 while (my ($k, $v) = each %$bridges) {
3861 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3862 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3867 if ($conf->{args
}) {
3868 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3872 push @$cmd, @$devices;
3873 push @$cmd, '-rtc', join(',', @$rtcFlags)
3874 if scalar(@$rtcFlags);
3875 push @$cmd, '-machine', join(',', @$machineFlags)
3876 if scalar(@$machineFlags);
3877 push @$cmd, '-global', join(',', @$globalFlags)
3878 if scalar(@$globalFlags);
3880 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3885 return "${var_run_tmpdir}/$vmid.vnc";
3891 my $res = vm_mon_cmd
($vmid, 'query-spice');
3893 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3897 my ($vmid, $qga, $name) = @_;
3898 my $sockettype = $qga ?
'qga' : 'qmp';
3899 my $ext = $name ?
'-'.$name : '';
3900 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3905 return "${var_run_tmpdir}/$vmid.pid";
3908 sub vm_devices_list
{
3911 my $res = vm_mon_cmd
($vmid, 'query-pci');
3912 my $devices_to_check = [];
3914 foreach my $pcibus (@$res) {
3915 push @$devices_to_check, @{$pcibus->{devices
}},
3918 while (@$devices_to_check) {
3920 for my $d (@$devices_to_check) {
3921 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3922 next if !$d->{'pci_bridge'};
3924 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3925 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3927 $devices_to_check = $to_check;
3930 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3931 foreach my $block (@$resblock) {
3932 if($block->{device
} =~ m/^drive-(\S+)/){
3937 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3938 foreach my $mice (@$resmice) {
3939 if ($mice->{name
} eq 'QEMU HID Tablet') {
3940 $devices->{tablet
} = 1;
3945 # for usb devices there is no query-usb
3946 # but we can iterate over the entries in
3947 # qom-list path=/machine/peripheral
3948 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3949 foreach my $per (@$resperipheral) {
3950 if ($per->{name
} =~ m/^usb\d+$/) {
3951 $devices->{$per->{name
}} = 1;
3959 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3961 my $q35 = machine_type_is_q35
($conf);
3963 my $devices_list = vm_devices_list
($vmid);
3964 return 1 if defined($devices_list->{$deviceid});
3966 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
3968 if ($deviceid eq 'tablet') {
3970 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3972 } elsif ($deviceid eq 'keyboard') {
3974 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3976 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3978 die "usb hotplug currently not reliable\n";
3979 # since we can't reliably hot unplug all added usb devices
3980 # and usb passthrough disables live migration
3981 # we disable usb hotplugging for now
3982 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3984 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3986 qemu_iothread_add
($vmid, $deviceid, $device);
3988 qemu_driveadd
($storecfg, $vmid, $device);
3989 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3991 qemu_deviceadd
($vmid, $devicefull);
3992 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3994 eval { qemu_drivedel
($vmid, $deviceid); };
3999 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4002 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4003 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4004 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4006 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4008 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4009 qemu_iothread_add
($vmid, $deviceid, $device);
4010 $devicefull .= ",iothread=iothread-$deviceid";
4013 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4014 $devicefull .= ",num_queues=$device->{queues}";
4017 qemu_deviceadd
($vmid, $devicefull);
4018 qemu_deviceaddverify
($vmid, $deviceid);
4020 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4022 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4023 qemu_driveadd
($storecfg, $vmid, $device);
4025 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4026 eval { qemu_deviceadd
($vmid, $devicefull); };
4028 eval { qemu_drivedel
($vmid, $deviceid); };
4033 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4035 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4037 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4038 my $use_old_bios_files = undef;
4039 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4041 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4042 qemu_deviceadd
($vmid, $netdevicefull);
4043 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4045 eval { qemu_netdevdel
($vmid, $deviceid); };
4050 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4053 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4054 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4056 qemu_deviceadd
($vmid, $devicefull);
4057 qemu_deviceaddverify
($vmid, $deviceid);
4060 die "can't hotplug device '$deviceid'\n";
4066 # fixme: this should raise exceptions on error!
4067 sub vm_deviceunplug
{
4068 my ($vmid, $conf, $deviceid) = @_;
4070 my $devices_list = vm_devices_list
($vmid);
4071 return 1 if !defined($devices_list->{$deviceid});
4073 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4075 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4077 qemu_devicedel
($vmid, $deviceid);
4079 } elsif ($deviceid =~ m/^usb\d+$/) {
4081 die "usb hotplug currently not reliable\n";
4082 # when unplugging usb devices this way,
4083 # there may be remaining usb controllers/hubs
4084 # so we disable it for now
4085 qemu_devicedel
($vmid, $deviceid);
4086 qemu_devicedelverify
($vmid, $deviceid);
4088 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4090 qemu_devicedel
($vmid, $deviceid);
4091 qemu_devicedelverify
($vmid, $deviceid);
4092 qemu_drivedel
($vmid, $deviceid);
4093 qemu_iothread_del
($conf, $vmid, $deviceid);
4095 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4097 qemu_devicedel
($vmid, $deviceid);
4098 qemu_devicedelverify
($vmid, $deviceid);
4099 qemu_iothread_del
($conf, $vmid, $deviceid);
4101 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4103 qemu_devicedel
($vmid, $deviceid);
4104 qemu_drivedel
($vmid, $deviceid);
4105 qemu_deletescsihw
($conf, $vmid, $deviceid);
4107 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4109 qemu_devicedel
($vmid, $deviceid);
4110 qemu_devicedelverify
($vmid, $deviceid);
4111 qemu_netdevdel
($vmid, $deviceid);
4114 die "can't unplug device '$deviceid'\n";
4120 sub qemu_deviceadd
{
4121 my ($vmid, $devicefull) = @_;
4123 $devicefull = "driver=".$devicefull;
4124 my %options = split(/[=,]/, $devicefull);
4126 vm_mon_cmd
($vmid, "device_add" , %options);
4129 sub qemu_devicedel
{
4130 my ($vmid, $deviceid) = @_;
4132 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4135 sub qemu_iothread_add
{
4136 my($vmid, $deviceid, $device) = @_;
4138 if ($device->{iothread
}) {
4139 my $iothreads = vm_iothreads_list
($vmid);
4140 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4144 sub qemu_iothread_del
{
4145 my($conf, $vmid, $deviceid) = @_;
4147 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4148 if ($device->{iothread
}) {
4149 my $iothreads = vm_iothreads_list
($vmid);
4150 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4154 sub qemu_objectadd
{
4155 my($vmid, $objectid, $qomtype) = @_;
4157 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4162 sub qemu_objectdel
{
4163 my($vmid, $objectid) = @_;
4165 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4171 my ($storecfg, $vmid, $device) = @_;
4173 my $drive = print_drive_full
($storecfg, $vmid, $device);
4174 $drive =~ s/\\/\\\\/g;
4175 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4177 # If the command succeeds qemu prints: "OK
"
4178 return 1 if $ret =~ m/OK/s;
4180 die "adding drive failed
: $ret\n";
4184 my($vmid, $deviceid) = @_;
4186 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4189 return 1 if $ret eq "";
4191 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4192 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4194 die "deleting drive
$deviceid failed
: $ret\n";
4197 sub qemu_deviceaddverify {
4198 my ($vmid, $deviceid) = @_;
4200 for (my $i = 0; $i <= 5; $i++) {
4201 my $devices_list = vm_devices_list($vmid);
4202 return 1 if defined($devices_list->{$deviceid});
4206 die "error on hotplug device
'$deviceid'\n";
4210 sub qemu_devicedelverify {
4211 my ($vmid, $deviceid) = @_;
4213 # need to verify that the device is correctly removed as device_del
4214 # is async and empty return is not reliable
4216 for (my $i = 0; $i <= 5; $i++) {
4217 my $devices_list = vm_devices_list($vmid);
4218 return 1 if !defined($devices_list->{$deviceid});
4222 die "error on hot-unplugging device
'$deviceid'\n";
4225 sub qemu_findorcreatescsihw {
4226 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4228 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4230 my $scsihwid="$controller_prefix$controller";
4231 my $devices_list = vm_devices_list($vmid);
4233 if(!defined($devices_list->{$scsihwid})) {
4234 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4240 sub qemu_deletescsihw {
4241 my ($conf, $vmid, $opt) = @_;
4243 my $device = parse_drive($opt, $conf->{$opt});
4245 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4246 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4250 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4252 my $devices_list = vm_devices_list($vmid);
4253 foreach my $opt (keys %{$devices_list}) {
4254 if (PVE::QemuServer::is_valid_drivename($opt)) {
4255 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4256 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4262 my $scsihwid="scsihw
$controller";
4264 vm_deviceunplug($vmid, $conf, $scsihwid);
4269 sub qemu_add_pci_bridge {
4270 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4276 print_pci_addr($device, $bridges, $arch, $machine_type);
4278 while (my ($k, $v) = each %$bridges) {
4281 return 1 if !defined($bridgeid) || $bridgeid < 1;
4283 my $bridge = "pci
.$bridgeid";
4284 my $devices_list = vm_devices_list($vmid);
4286 if (!defined($devices_list->{$bridge})) {
4287 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4293 sub qemu_set_link_status {
4294 my ($vmid, $device, $up) = @_;
4296 vm_mon_cmd($vmid, "set_link
", name => $device,
4297 up => $up ? JSON::true : JSON::false);
4300 sub qemu_netdevadd {
4301 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4303 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4304 my %options = split(/[=,]/, $netdev);
4306 vm_mon_cmd($vmid, "netdev_add
", %options);
4310 sub qemu_netdevdel {
4311 my ($vmid, $deviceid) = @_;
4313 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4316 sub qemu_usb_hotplug {
4317 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4321 # remove the old one first
4322 vm_deviceunplug($vmid, $conf, $deviceid);
4324 # check if xhci controller is necessary and available
4325 if ($device->{usb3}) {
4327 my $devicelist = vm_devices_list($vmid);
4329 if (!$devicelist->{xhci}) {
4330 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4331 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4334 my $d = parse_usb_device($device->{host});
4335 $d->{usb3} = $device->{usb3};
4338 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4341 sub qemu_cpu_hotplug {
4342 my ($vmid, $conf, $vcpus) = @_;
4344 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4347 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4348 $sockets = $conf->{sockets} if $conf->{sockets};
4349 my $cores = $conf->{cores} || 1;
4350 my $maxcpus = $sockets * $cores;
4352 $vcpus = $maxcpus if !$vcpus;
4354 die "you can
't add more vcpus than maxcpus\n"
4355 if $vcpus > $maxcpus;
4357 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4359 if ($vcpus < $currentvcpus) {
4361 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4363 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4364 qemu_devicedel($vmid, "cpu$i");
4366 my $currentrunningvcpus = undef;
4368 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4369 last if scalar(@{$currentrunningvcpus}) == $i-1;
4370 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4374 #update conf after each succesfull cpu unplug
4375 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4376 PVE::QemuConfig->write_config($vmid, $conf);
4379 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4385 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4386 die "vcpus in running vm does not match its configuration\n"
4387 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4389 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4391 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4392 my $cpustr = print_cpu_device($conf, $i);
4393 qemu_deviceadd($vmid, $cpustr);
4396 my $currentrunningvcpus = undef;
4398 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4399 last if scalar(@{$currentrunningvcpus}) == $i;
4400 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4404 #update conf after each succesfull cpu hotplug
4405 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4406 PVE::QemuConfig->write_config($vmid, $conf);
4410 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4411 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4416 sub qemu_block_set_io_throttle {
4417 my ($vmid, $deviceid,
4418 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4419 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4420 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4421 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4423 return if !check_running($vmid) ;
4425 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4427 bps_rd => int($bps_rd),
4428 bps_wr => int($bps_wr),
4430 iops_rd => int($iops_rd),
4431 iops_wr => int($iops_wr),
4432 bps_max => int($bps_max),
4433 bps_rd_max => int($bps_rd_max),
4434 bps_wr_max => int($bps_wr_max),
4435 iops_max => int($iops_max),
4436 iops_rd_max => int($iops_rd_max),
4437 iops_wr_max => int($iops_wr_max),
4438 bps_max_length => int($bps_max_length),
4439 bps_rd_max_length => int($bps_rd_max_length),
4440 bps_wr_max_length => int($bps_wr_max_length),
4441 iops_max_length => int($iops_max_length),
4442 iops_rd_max_length => int($iops_rd_max_length),
4443 iops_wr_max_length => int($iops_wr_max_length),
4448 # old code, only used to shutdown old VM after update
4450 my ($fh, $timeout) = @_;
4452 my $sel = new IO::Select;
4459 while (scalar (@ready = $sel->can_read($timeout))) {
4461 if ($count = $fh->sysread($buf, 8192)) {
4462 if ($buf =~ /^(.*)\(qemu\) $/s) {
4469 if (!defined($count)) {
4476 die "monitor read timeout\n" if !scalar(@ready);
4481 sub qemu_block_resize {
4482 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4484 my $running = check_running($vmid);
4486 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4488 return if !$running;
4490 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4494 sub qemu_volume_snapshot {
4495 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4497 my $running = check_running($vmid);
4499 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4500 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4502 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4506 sub qemu_volume_snapshot_delete {
4507 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4509 my $running = check_running($vmid);
4514 my $conf = PVE::QemuConfig->load_config($vmid);
4515 foreach_drive($conf, sub {
4516 my ($ds, $drive) = @_;
4517 $running = 1 if $drive->{file} eq $volid;
4521 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4522 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4524 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4528 sub set_migration_caps {
4534 "auto-converge" => 1,
4536 "x-rdma-pin-all" => 0,
4541 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4543 for my $supported_capability (@$supported_capabilities) {
4545 capability => $supported_capability->{capability},
4546 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4550 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4553 my $fast_plug_option = {
4561 'vmstatestorage
' => 1,
4564 # hotplug changes in [PENDING]
4565 # $selection hash can be used to only apply specified options, for
4566 # example: { cores => 1 } (only apply changed 'cores
')
4567 # $errors ref is used to return error messages
4568 sub vmconfig_hotplug_pending {
4569 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4571 my $defaults = load_defaults();
4572 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4574 # commit values which do not have any impact on running VM first
4575 # Note: those option cannot raise errors, we we do not care about
4576 # $selection and always apply them.
4578 my $add_error = sub {
4579 my ($opt, $msg) = @_;
4580 $errors->{$opt} = "hotplug problem - $msg";
4584 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4585 if ($fast_plug_option->{$opt}) {
4586 $conf->{$opt} = $conf->{pending}->{$opt};
4587 delete $conf->{pending}->{$opt};
4593 PVE::QemuConfig->write_config($vmid, $conf);
4594 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4597 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4599 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4600 while (my ($opt, $force) = each %$pending_delete_hash) {
4601 next if $selection && !$selection->{$opt};
4603 if ($opt eq 'hotplug
') {
4604 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4605 } elsif ($opt eq 'tablet
') {
4606 die "skip\n" if !$hotplug_features->{usb};
4607 if ($defaults->{tablet}) {
4608 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4609 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4610 if $arch eq 'aarch64
';
4612 vm_deviceunplug($vmid, $conf, 'tablet
');
4613 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4615 } elsif ($opt =~ m/^usb\d+/) {
4617 # since we cannot reliably hot unplug usb devices
4618 # we are disabling it
4619 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4620 vm_deviceunplug($vmid, $conf, $opt);
4621 } elsif ($opt eq 'vcpus
') {
4622 die "skip\n" if !$hotplug_features->{cpu};
4623 qemu_cpu_hotplug($vmid, $conf, undef);
4624 } elsif ($opt eq 'balloon
') {
4625 # enable balloon device is not hotpluggable
4626 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4627 # here we reset the ballooning value to memory
4628 my $balloon = $conf->{memory} || $defaults->{memory};
4629 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4630 } elsif ($fast_plug_option->{$opt}) {
4632 } elsif ($opt =~ m/^net(\d+)$/) {
4633 die "skip\n" if !$hotplug_features->{network};
4634 vm_deviceunplug($vmid, $conf, $opt);
4635 } elsif (is_valid_drivename($opt)) {
4636 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4637 vm_deviceunplug($vmid, $conf, $opt);
4638 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4639 } elsif ($opt =~ m/^memory$/) {
4640 die "skip\n" if !$hotplug_features->{memory};
4641 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4642 } elsif ($opt eq 'cpuunits
') {
4643 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4644 } elsif ($opt eq 'cpulimit
') {
4645 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4651 &$add_error($opt, $err) if $err ne "skip\n";
4653 # save new config if hotplug was successful
4654 delete $conf->{$opt};
4655 vmconfig_undelete_pending_option($conf, $opt);
4656 PVE::QemuConfig->write_config($vmid, $conf);
4657 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4661 my $apply_pending_cloudinit;
4662 $apply_pending_cloudinit = sub {
4663 my ($key, $value) = @_;
4664 $apply_pending_cloudinit = sub {}; # once is enough
4666 my @cloudinit_opts = keys %$confdesc_cloudinit;
4667 foreach my $opt (keys %{$conf->{pending}}) {
4668 next if !grep { $_ eq $opt } @cloudinit_opts;
4669 $conf->{$opt} = delete $conf->{pending}->{$opt};
4672 my $new_conf = { %$conf };
4673 $new_conf->{$key} = $value;
4674 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4677 foreach my $opt (keys %{$conf->{pending}}) {
4678 next if $selection && !$selection->{$opt};
4679 my $value = $conf->{pending}->{$opt};
4681 if ($opt eq 'hotplug
') {
4682 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4683 } elsif ($opt eq 'tablet
') {
4684 die "skip\n" if !$hotplug_features->{usb};
4686 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4687 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4688 if $arch eq 'aarch64
';
4689 } elsif ($value == 0) {
4690 vm_deviceunplug($vmid, $conf, 'tablet
');
4691 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4693 } elsif ($opt =~ m/^usb\d+$/) {
4695 # since we cannot reliably hot unplug usb devices
4696 # we are disabling it
4697 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4698 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4699 die "skip\n" if !$d;
4700 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4701 } elsif ($opt eq 'vcpus
') {
4702 die "skip\n" if !$hotplug_features->{cpu};
4703 qemu_cpu_hotplug($vmid, $conf, $value);
4704 } elsif ($opt eq 'balloon
') {
4705 # enable/disable balloning device is not hotpluggable
4706 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4707 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4708 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4710 # allow manual ballooning if shares is set to zero
4711 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4712 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4713 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4715 } elsif ($opt =~ m/^net(\d+)$/) {
4716 # some changes can be done without hotplug
4717 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4718 $vmid, $opt, $value, $arch, $machine_type);
4719 } elsif (is_valid_drivename($opt)) {
4720 # some changes can be done without hotplug
4721 my $drive = parse_drive($opt, $value);
4722 if (drive_is_cloudinit($drive)) {
4723 &$apply_pending_cloudinit($opt, $value);
4725 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4726 $vmid, $opt, $value, 1, $arch, $machine_type);
4727 } elsif ($opt =~ m/^memory$/) { #dimms
4728 die "skip\n" if !$hotplug_features->{memory};
4729 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4730 } elsif ($opt eq 'cpuunits
') {
4731 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4732 } elsif ($opt eq 'cpulimit
') {
4733 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4734 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4736 die "skip\n"; # skip non-hot-pluggable options
4740 &$add_error($opt, $err) if $err ne "skip\n";
4742 # save new config if hotplug was successful
4743 $conf->{$opt} = $value;
4744 delete $conf->{pending}->{$opt};
4745 PVE::QemuConfig->write_config($vmid, $conf);
4746 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4751 sub try_deallocate_drive {
4752 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4754 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4755 my $volid = $drive->{file};
4756 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4757 my $sid = PVE::Storage::parse_volume_id($volid);
4758 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4760 # check if the disk is really unused
4761 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4762 if is_volume_in_use($storecfg, $conf, $key, $volid);
4763 PVE::Storage::vdisk_free($storecfg, $volid);
4766 # If vm is not owner of this disk remove from config
4774 sub vmconfig_delete_or_detach_drive {
4775 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4777 my $drive = parse_drive($opt, $conf->{$opt});
4779 my $rpcenv = PVE::RPCEnvironment::get();
4780 my $authuser = $rpcenv->get_user();
4783 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4784 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4786 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4790 sub vmconfig_apply_pending {
4791 my ($vmid, $conf, $storecfg) = @_;
4795 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4796 while (my ($opt, $force) = each %$pending_delete_hash) {
4797 die "internal error" if $opt =~ m/^unused/;
4798 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4799 if (!defined($conf->{$opt})) {
4800 vmconfig_undelete_pending_option($conf, $opt);
4801 PVE::QemuConfig->write_config($vmid, $conf);
4802 } elsif (is_valid_drivename($opt)) {
4803 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4804 vmconfig_undelete_pending_option($conf, $opt);
4805 delete $conf->{$opt};
4806 PVE::QemuConfig->write_config($vmid, $conf);
4808 vmconfig_undelete_pending_option($conf, $opt);
4809 delete $conf->{$opt};
4810 PVE::QemuConfig->write_config($vmid, $conf);
4814 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4816 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4817 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4819 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4820 # skip if nothing changed
4821 } elsif (is_valid_drivename($opt)) {
4822 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4823 if defined($conf->{$opt});
4824 $conf->{$opt} = $conf->{pending}->{$opt};
4826 $conf->{$opt} = $conf->{pending}->{$opt};
4829 delete $conf->{pending}->{$opt};
4830 PVE::QemuConfig->write_config($vmid, $conf);
4834 my $safe_num_ne = sub {
4837 return 0 if !defined($a) && !defined($b);
4838 return 1 if !defined($a);
4839 return 1 if !defined($b);
4844 my $safe_string_ne = sub {
4847 return 0 if !defined($a) && !defined($b);
4848 return 1 if !defined($a);
4849 return 1 if !defined($b);
4854 sub vmconfig_update_net {
4855 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4857 my $newnet = parse_net($value);
4859 if ($conf->{$opt}) {
4860 my $oldnet = parse_net($conf->{$opt});
4862 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4863 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4864 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4865 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4867 # for non online change, we try to hot-unplug
4868 die "skip\n" if !$hotplug;
4869 vm_deviceunplug($vmid, $conf, $opt);
4872 die "internal error" if $opt !~ m/net(\d+)/;
4873 my $iface = "tap${vmid}i$1";
4875 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4876 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4877 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4878 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4879 PVE::Network::tap_unplug($iface);
4880 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4881 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4882 # Rate can be applied on its own but any change above needs to
4883 # include the rate in tap_plug since OVS resets everything.
4884 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4887 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4888 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4896 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4902 sub vmconfig_update_disk {
4903 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
4905 # fixme: do we need force?
4907 my $drive = parse_drive($opt, $value);
4909 if ($conf->{$opt}) {
4911 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4913 my $media = $drive->{media} || 'disk
';
4914 my $oldmedia = $old_drive->{media} || 'disk
';
4915 die "unable to change media type\n" if $media ne $oldmedia;
4917 if (!drive_is_cdrom($old_drive)) {
4919 if ($drive->{file} ne $old_drive->{file}) {
4921 die "skip\n" if !$hotplug;
4923 # unplug and register as unused
4924 vm_deviceunplug($vmid, $conf, $opt);
4925 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4928 # update existing disk
4930 # skip non hotpluggable value
4931 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4932 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4933 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4934 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4939 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4940 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4941 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4942 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4943 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4944 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4945 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4946 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4947 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4948 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4949 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4950 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4951 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4952 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4953 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4954 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4955 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4956 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4958 qemu_block_set_io_throttle($vmid,"drive-$opt",
4959 ($drive->{mbps} || 0)*1024*1024,
4960 ($drive->{mbps_rd} || 0)*1024*1024,
4961 ($drive->{mbps_wr} || 0)*1024*1024,
4962 $drive->{iops} || 0,
4963 $drive->{iops_rd} || 0,
4964 $drive->{iops_wr} || 0,
4965 ($drive->{mbps_max} || 0)*1024*1024,
4966 ($drive->{mbps_rd_max} || 0)*1024*1024,
4967 ($drive->{mbps_wr_max} || 0)*1024*1024,
4968 $drive->{iops_max} || 0,
4969 $drive->{iops_rd_max} || 0,
4970 $drive->{iops_wr_max} || 0,
4971 $drive->{bps_max_length} || 1,
4972 $drive->{bps_rd_max_length} || 1,
4973 $drive->{bps_wr_max_length} || 1,
4974 $drive->{iops_max_length} || 1,
4975 $drive->{iops_rd_max_length} || 1,
4976 $drive->{iops_wr_max_length} || 1);
4985 if ($drive->{file} eq 'none
') {
4986 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4987 if (drive_is_cloudinit($old_drive)) {
4988 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4991 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4992 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4993 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5001 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5003 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5004 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5008 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5009 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5011 PVE::QemuConfig->lock_config($vmid, sub {
5012 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5014 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5016 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5018 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5020 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5021 vmconfig_apply_pending($vmid, $conf, $storecfg);
5022 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5025 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5027 my $defaults = load_defaults();
5029 # set environment variable useful inside network script
5030 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5032 my $local_volumes = {};
5034 if ($targetstorage) {
5035 foreach_drive($conf, sub {
5036 my ($ds, $drive) = @_;
5038 return if drive_is_cdrom($drive);
5040 my $volid = $drive->{file};
5044 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5046 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5047 return if $scfg->{shared};
5048 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5053 foreach my $opt (sort keys %$local_volumes) {
5055 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5056 my $drive = parse_drive($opt, $conf->{$opt});
5058 #if remote storage is specified, use default format
5059 if ($targetstorage && $targetstorage ne "1") {
5060 $storeid = $targetstorage;
5061 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5062 $format = $defFormat;
5064 #else we use same format than original
5065 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5066 $format = qemu_img_format($scfg, $volid);
5069 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5070 my $newdrive = $drive;
5071 $newdrive->{format} = $format;
5072 $newdrive->{file} = $newvolid;
5073 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5074 $local_volumes->{$opt} = $drivestr;
5075 #pass drive to conf for command line
5076 $conf->{$opt} = $drivestr;
5080 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5082 my $migrate_port = 0;
5085 if ($statefile eq 'tcp
') {
5086 my $localip = "localhost";
5087 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5088 my $nodename = PVE::INotify::nodename();
5090 if (!defined($migration_type)) {
5091 if (defined($datacenterconf->{migration}->{type})) {
5092 $migration_type = $datacenterconf->{migration}->{type};
5094 $migration_type = 'secure
';
5098 if ($migration_type eq 'insecure
') {
5099 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5100 if ($migrate_network_addr) {
5101 $localip = $migrate_network_addr;
5103 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5106 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5109 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5110 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5111 $migrate_uri = "tcp:${localip}:${migrate_port}";
5112 push @$cmd, '-incoming
', $migrate_uri;
5115 } elsif ($statefile eq 'unix
') {
5116 # should be default for secure migrations as a ssh TCP forward
5117 # tunnel is not deterministic reliable ready and fails regurarly
5118 # to set up in time, so use UNIX socket forwards
5119 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5120 unlink $socket_addr;
5122 $migrate_uri = "unix:$socket_addr";
5124 push @$cmd, '-incoming
', $migrate_uri;
5128 push @$cmd, '-loadstate
', $statefile;
5135 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5136 my $d = parse_hostpci($conf->{"hostpci$i"});
5138 my $pcidevices = $d->{pciid};
5139 foreach my $pcidevice (@$pcidevices) {
5140 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
5142 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5143 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5144 die "no pci device info for device '$pciid'\n" if !$info;
5145 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5146 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5147 die "can
't reset pci device '$pciid'\n"
5148 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5152 PVE::Storage::activate_volumes($storecfg, $vollist);
5154 if (!check_running($vmid, 1)) {
5156 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5157 outfunc => sub {}, errfunc => sub {});
5161 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5162 : $defaults->{cpuunits};
5164 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5165 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5168 Slice => 'qemu
.slice
',
5170 CPUShares => $cpuunits
5173 if (my $cpulimit = $conf->{cpulimit}) {
5174 $properties{CPUQuota} = int($cpulimit * 100);
5176 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5178 my $run_qemu = sub {
5179 PVE::Tools::run_fork sub {
5180 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5181 run_command($cmd, %run_params);
5185 if ($conf->{hugepages}) {
5188 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5189 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5191 PVE::QemuServer::Memory::hugepages_mount();
5192 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5194 eval { $run_qemu->() };
5196 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5200 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5202 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5205 eval { $run_qemu->() };
5209 # deactivate volumes if start fails
5210 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5211 die "start failed: $err";
5214 print "migration listens on $migrate_uri\n" if $migrate_uri;
5216 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5217 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5221 #start nbd server for storage migration
5222 if ($targetstorage) {
5223 my $nodename = PVE::INotify::nodename();
5224 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5225 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5226 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5227 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5229 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5231 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5233 foreach my $opt (sort keys %$local_volumes) {
5234 my $volid = $local_volumes->{$opt};
5235 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5236 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5237 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5241 if ($migratedfrom) {
5243 set_migration_caps($vmid);
5248 print "spice listens on port $spice_port\n";
5249 if ($spice_ticket) {
5250 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5251 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5256 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5257 if !$statefile && $conf->{balloon};
5259 foreach my $opt (keys %$conf) {
5260 next if $opt !~ m/^net\d+$/;
5261 my $nicconf = parse_net($conf->{$opt});
5262 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5266 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5267 path => "machine/peripheral/balloon0",
5268 property => "guest-stats-polling-interval",
5269 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5275 my ($vmid, $execute, %params) = @_;
5277 my $cmd = { execute => $execute, arguments => \%params };
5278 vm_qmp_command($vmid, $cmd);
5281 sub vm_mon_cmd_nocheck {
5282 my ($vmid, $execute, %params) = @_;
5284 my $cmd = { execute => $execute, arguments => \%params };
5285 vm_qmp_command($vmid, $cmd, 1);
5288 sub vm_qmp_command {
5289 my ($vmid, $cmd, $nocheck) = @_;
5294 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5295 $timeout = $cmd->{arguments}->{timeout};
5296 delete $cmd->{arguments}->{timeout};
5300 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5301 my $sname = qmp_socket($vmid);
5302 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5303 my $qmpclient = PVE::QMPClient->new();
5305 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5307 die "unable to open monitor socket\n";
5311 syslog("err", "VM $vmid qmp command failed - $err");
5318 sub vm_human_monitor_command {
5319 my ($vmid, $cmdline) = @_;
5324 execute => 'human-monitor-command
',
5325 arguments => { 'command-line
' => $cmdline},
5328 return vm_qmp_command($vmid, $cmd);
5331 sub vm_commandline {
5332 my ($storecfg, $vmid) = @_;
5334 my $conf = PVE::QemuConfig->load_config($vmid);
5336 my $defaults = load_defaults();
5338 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5340 return PVE::Tools::cmd2string($cmd);
5344 my ($vmid, $skiplock) = @_;
5346 PVE::QemuConfig->lock_config($vmid, sub {
5348 my $conf = PVE::QemuConfig->load_config($vmid);
5350 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5352 vm_mon_cmd($vmid, "system_reset");
5356 sub get_vm_volumes {
5360 foreach_volid($conf, sub {
5361 my ($volid, $attr) = @_;
5363 return if $volid =~ m|^/|;
5365 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5368 push @$vollist, $volid;
5374 sub vm_stop_cleanup {
5375 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5380 my $vollist = get_vm_volumes($conf);
5381 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5384 foreach my $ext (qw(mon qmp pid vnc qga)) {
5385 unlink "/var/run/qemu-server/${vmid}.$ext";
5388 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5390 warn $@ if $@; # avoid errors - just warn
5393 # Note: use $nockeck to skip tests if VM configuration file exists.
5394 # We need that when migration VMs to other nodes (files already moved)
5395 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5397 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5399 $force = 1 if !defined($force) && !$shutdown;
5402 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5403 kill 15, $pid if $pid;
5404 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5405 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5409 PVE
::QemuConfig-
>lock_config($vmid, sub {
5411 my $pid = check_running
($vmid, $nocheck);
5416 $conf = PVE
::QemuConfig-
>load_config($vmid);
5417 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5418 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5419 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5420 $timeout = $opts->{down
} if $opts->{down
};
5424 $timeout = 60 if !defined($timeout);
5428 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5429 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5431 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5434 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5441 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5446 if ($count >= $timeout) {
5448 warn "VM still running - terminating now with SIGTERM\n";
5451 die "VM quit/powerdown failed - got timeout\n";
5454 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5459 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5462 die "VM quit/powerdown failed\n";
5470 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5475 if ($count >= $timeout) {
5476 warn "VM still running - terminating now with SIGKILL\n";
5481 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5486 my ($vmid, $skiplock) = @_;
5488 PVE
::QemuConfig-
>lock_config($vmid, sub {
5490 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5492 PVE
::QemuConfig-
>check_lock($conf)
5493 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5495 vm_mon_cmd
($vmid, "stop");
5500 my ($vmid, $skiplock, $nocheck) = @_;
5502 PVE
::QemuConfig-
>lock_config($vmid, sub {
5504 my $res = vm_mon_cmd
($vmid, 'query-status');
5505 my $resume_cmd = 'cont';
5507 if ($res->{status
} && $res->{status
} eq 'suspended') {
5508 $resume_cmd = 'system_wakeup';
5513 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5515 PVE
::QemuConfig-
>check_lock($conf)
5516 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5518 vm_mon_cmd
($vmid, $resume_cmd);
5521 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5527 my ($vmid, $skiplock, $key) = @_;
5529 PVE
::QemuConfig-
>lock_config($vmid, sub {
5531 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5533 # there is no qmp command, so we use the human monitor command
5534 vm_human_monitor_command
($vmid, "sendkey $key");
5539 my ($storecfg, $vmid, $skiplock) = @_;
5541 PVE
::QemuConfig-
>lock_config($vmid, sub {
5543 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5545 if (!check_running
($vmid)) {
5546 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5548 die "VM $vmid is running - destroy failed\n";
5553 # vzdump restore implementaion
5555 sub tar_archive_read_firstfile
{
5556 my $archive = shift;
5558 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5560 # try to detect archive type first
5561 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5562 die "unable to open file '$archive'\n";
5563 my $firstfile = <$fh>;
5567 die "ERROR: archive contaions no data\n" if !$firstfile;
5573 sub tar_restore_cleanup
{
5574 my ($storecfg, $statfile) = @_;
5576 print STDERR
"starting cleanup\n";
5578 if (my $fd = IO
::File-
>new($statfile, "r")) {
5579 while (defined(my $line = <$fd>)) {
5580 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5583 if ($volid =~ m
|^/|) {
5584 unlink $volid || die 'unlink failed\n';
5586 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5588 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5590 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5592 print STDERR
"unable to parse line in statfile - $line";
5599 sub restore_archive
{
5600 my ($archive, $vmid, $user, $opts) = @_;
5602 my $format = $opts->{format
};
5605 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5606 $format = 'tar' if !$format;
5608 } elsif ($archive =~ m/\.tar$/) {
5609 $format = 'tar' if !$format;
5610 } elsif ($archive =~ m/.tar.lzo$/) {
5611 $format = 'tar' if !$format;
5613 } elsif ($archive =~ m/\.vma$/) {
5614 $format = 'vma' if !$format;
5615 } elsif ($archive =~ m/\.vma\.gz$/) {
5616 $format = 'vma' if !$format;
5618 } elsif ($archive =~ m/\.vma\.lzo$/) {
5619 $format = 'vma' if !$format;
5622 $format = 'vma' if !$format; # default
5625 # try to detect archive format
5626 if ($format eq 'tar') {
5627 return restore_tar_archive
($archive, $vmid, $user, $opts);
5629 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5633 sub restore_update_config_line
{
5634 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5636 return if $line =~ m/^\#qmdump\#/;
5637 return if $line =~ m/^\#vzdump\#/;
5638 return if $line =~ m/^lock:/;
5639 return if $line =~ m/^unused\d+:/;
5640 return if $line =~ m/^parent:/;
5641 return if $line =~ m/^template:/; # restored VM is never a template
5643 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5644 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5645 # try to convert old 1.X settings
5646 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5647 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5648 my ($model, $macaddr) = split(/\=/, $devconfig);
5649 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5652 bridge
=> "vmbr$ind",
5653 macaddr
=> $macaddr,
5655 my $netstr = print_net
($net);
5657 print $outfd "net$cookie->{netcount}: $netstr\n";
5658 $cookie->{netcount
}++;
5660 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5661 my ($id, $netstr) = ($1, $2);
5662 my $net = parse_net
($netstr);
5663 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5664 $netstr = print_net
($net);
5665 print $outfd "$id: $netstr\n";
5666 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5669 my $di = parse_drive
($virtdev, $value);
5670 if (defined($di->{backup
}) && !$di->{backup
}) {
5671 print $outfd "#$line";
5672 } elsif ($map->{$virtdev}) {
5673 delete $di->{format
}; # format can change on restore
5674 $di->{file
} = $map->{$virtdev};
5675 $value = print_drive
($vmid, $di);
5676 print $outfd "$virtdev: $value\n";
5680 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5682 if ($vmgenid ne '0') {
5683 # always generate a new vmgenid if there was a valid one setup
5684 $vmgenid = generate_uuid
();
5686 print $outfd "vmgenid: $vmgenid\n";
5687 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5688 my ($uuid, $uuid_str);
5689 UUID
::generate
($uuid);
5690 UUID
::unparse
($uuid, $uuid_str);
5691 my $smbios1 = parse_smbios1
($2);
5692 $smbios1->{uuid
} = $uuid_str;
5693 print $outfd $1.print_smbios1
($smbios1)."\n";
5700 my ($cfg, $vmid) = @_;
5702 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5704 my $volid_hash = {};
5705 foreach my $storeid (keys %$info) {
5706 foreach my $item (@{$info->{$storeid}}) {
5707 next if !($item->{volid
} && $item->{size
});
5708 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5709 $volid_hash->{$item->{volid
}} = $item;
5716 sub is_volume_in_use
{
5717 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5719 my $path = PVE
::Storage
::path
($storecfg, $volid);
5721 my $scan_config = sub {
5722 my ($cref, $snapname) = @_;
5724 foreach my $key (keys %$cref) {
5725 my $value = $cref->{$key};
5726 if (is_valid_drivename
($key)) {
5727 next if $skip_drive && $key eq $skip_drive;
5728 my $drive = parse_drive
($key, $value);
5729 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5730 return 1 if $volid eq $drive->{file
};
5731 if ($drive->{file
} =~ m!^/!) {
5732 return 1 if $drive->{file
} eq $path;
5734 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5736 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5738 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5746 return 1 if &$scan_config($conf);
5750 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5751 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5757 sub update_disksize
{
5758 my ($vmid, $conf, $volid_hash) = @_;
5761 my $prefix = "VM $vmid:";
5763 # used and unused disks
5764 my $referenced = {};
5766 # Note: it is allowed to define multiple storages with same path (alias), so
5767 # we need to check both 'volid' and real 'path' (two different volid can point
5768 # to the same path).
5770 my $referencedpath = {};
5773 foreach my $opt (keys %$conf) {
5774 if (is_valid_drivename
($opt)) {
5775 my $drive = parse_drive
($opt, $conf->{$opt});
5776 my $volid = $drive->{file
};
5779 $referenced->{$volid} = 1;
5780 if ($volid_hash->{$volid} &&
5781 (my $path = $volid_hash->{$volid}->{path
})) {
5782 $referencedpath->{$path} = 1;
5785 next if drive_is_cdrom
($drive);
5786 next if !$volid_hash->{$volid};
5788 $drive->{size
} = $volid_hash->{$volid}->{size
};
5789 my $new = print_drive
($vmid, $drive);
5790 if ($new ne $conf->{$opt}) {
5792 $conf->{$opt} = $new;
5793 print "$prefix update disk '$opt' information.\n";
5798 # remove 'unusedX' entry if volume is used
5799 foreach my $opt (keys %$conf) {
5800 next if $opt !~ m/^unused\d+$/;
5801 my $volid = $conf->{$opt};
5802 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5803 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5804 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5806 delete $conf->{$opt};
5809 $referenced->{$volid} = 1;
5810 $referencedpath->{$path} = 1 if $path;
5813 foreach my $volid (sort keys %$volid_hash) {
5814 next if $volid =~ m/vm-$vmid-state-/;
5815 next if $referenced->{$volid};
5816 my $path = $volid_hash->{$volid}->{path
};
5817 next if !$path; # just to be sure
5818 next if $referencedpath->{$path};
5820 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5821 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5822 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5829 my ($vmid, $nolock, $dryrun) = @_;
5831 my $cfg = PVE
::Storage
::config
();
5833 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5834 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5835 foreach my $stor (keys %{$cfg->{ids
}}) {
5836 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5839 print "rescan volumes...\n";
5840 my $volid_hash = scan_volids
($cfg, $vmid);
5842 my $updatefn = sub {
5845 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5847 PVE
::QemuConfig-
>check_lock($conf);
5850 foreach my $volid (keys %$volid_hash) {
5851 my $info = $volid_hash->{$volid};
5852 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5855 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5857 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5860 if (defined($vmid)) {
5864 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5867 my $vmlist = config_list
();
5868 foreach my $vmid (keys %$vmlist) {
5872 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5878 sub restore_vma_archive
{
5879 my ($archive, $vmid, $user, $opts, $comp) = @_;
5881 my $readfrom = $archive;
5883 my $cfg = PVE
::Storage
::config
();
5885 my $bwlimit = $opts->{bwlimit
};
5887 my $dbg_cmdstring = '';
5888 my $add_pipe = sub {
5890 push @$commands, $cmd;
5891 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5892 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5897 if ($archive eq '-') {
5900 # If we use a backup from a PVE defined storage we also consider that
5901 # storage's rate limit:
5902 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5903 if (defined($volid)) {
5904 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5905 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5907 print STDERR
"applying read rate limit: $readlimit\n";
5908 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5909 $add_pipe->($cstream);
5916 if ($comp eq 'gzip') {
5917 $cmd = ['zcat', $readfrom];
5918 } elsif ($comp eq 'lzop') {
5919 $cmd = ['lzop', '-d', '-c', $readfrom];
5921 die "unknown compression method '$comp'\n";
5926 my $tmpdir = "/var/tmp/vzdumptmp$$";
5929 # disable interrupts (always do cleanups)
5933 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5935 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5936 POSIX
::mkfifo
($mapfifo, 0600);
5939 my $openfifo = sub {
5940 open($fifofh, '>', $mapfifo) || die $!;
5943 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5950 my $rpcenv = PVE
::RPCEnvironment
::get
();
5952 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5953 my $tmpfn = "$conffile.$$.tmp";
5955 # Note: $oldconf is undef if VM does not exists
5956 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5957 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5961 my $print_devmap = sub {
5962 my $virtdev_hash = {};
5964 my $cfgfn = "$tmpdir/qemu-server.conf";
5966 # we can read the config - that is already extracted
5967 my $fh = IO
::File-
>new($cfgfn, "r") ||
5968 "unable to read qemu-server.conf - $!\n";
5970 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5972 my $pve_firewall_dir = '/etc/pve/firewall';
5973 mkdir $pve_firewall_dir; # make sure the dir exists
5974 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5977 while (defined(my $line = <$fh>)) {
5978 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5979 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5980 die "archive does not contain data for drive '$virtdev'\n"
5981 if !$devinfo->{$devname};
5982 if (defined($opts->{storage
})) {
5983 $storeid = $opts->{storage
} || 'local';
5984 } elsif (!$storeid) {
5987 $format = 'raw' if !$format;
5988 $devinfo->{$devname}->{devname
} = $devname;
5989 $devinfo->{$devname}->{virtdev
} = $virtdev;
5990 $devinfo->{$devname}->{format
} = $format;
5991 $devinfo->{$devname}->{storeid
} = $storeid;
5993 # check permission on storage
5994 my $pool = $opts->{pool
}; # todo: do we need that?
5995 if ($user ne 'root@pam') {
5996 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5999 $storage_limits{$storeid} = $bwlimit;
6001 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6005 foreach my $key (keys %storage_limits) {
6006 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6008 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6009 $storage_limits{$key} = $limit * 1024;
6012 foreach my $devname (keys %$devinfo) {
6013 die "found no device mapping information for device '$devname'\n"
6014 if !$devinfo->{$devname}->{virtdev
};
6017 # create empty/temp config
6019 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6020 foreach_drive
($oldconf, sub {
6021 my ($ds, $drive) = @_;
6023 return if drive_is_cdrom
($drive);
6025 my $volid = $drive->{file
};
6027 return if !$volid || $volid =~ m
|^/|;
6029 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6030 return if !$path || !$owner || ($owner != $vmid);
6032 # Note: only delete disk we want to restore
6033 # other volumes will become unused
6034 if ($virtdev_hash->{$ds}) {
6035 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6042 # delete vmstate files
6043 # since after the restore we have no snapshots anymore
6044 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6045 my $snap = $oldconf->{snapshots
}->{$snapname};
6046 if ($snap->{vmstate
}) {
6047 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6056 foreach my $virtdev (sort keys %$virtdev_hash) {
6057 my $d = $virtdev_hash->{$virtdev};
6058 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6059 my $storeid = $d->{storeid
};
6060 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6063 if (my $limit = $storage_limits{$storeid}) {
6064 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6067 # test if requested format is supported
6068 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6069 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6070 $d->{format
} = $defFormat if !$supported;
6072 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6073 $d->{format
}, undef, $alloc_size);
6074 print STDERR
"new volume ID is '$volid'\n";
6075 $d->{volid
} = $volid;
6076 my $path = PVE
::Storage
::path
($cfg, $volid);
6078 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6080 my $write_zeros = 1;
6081 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6085 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6087 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6088 $map->{$virtdev} = $volid;
6091 $fh->seek(0, 0) || die "seek failed - $!\n";
6093 my $outfd = new IO
::File
($tmpfn, "w") ||
6094 die "unable to write config for VM $vmid\n";
6096 my $cookie = { netcount
=> 0 };
6097 while (defined(my $line = <$fh>)) {
6098 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6111 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6112 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6114 $oldtimeout = alarm($timeout);
6121 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6122 my ($dev_id, $size, $devname) = ($1, $2, $3);
6123 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6124 } elsif ($line =~ m/^CTIME: /) {
6125 # we correctly received the vma config, so we can disable
6126 # the timeout now for disk allocation (set to 10 minutes, so
6127 # that we always timeout if something goes wrong)
6130 print $fifofh "done\n";
6131 my $tmp = $oldtimeout || 0;
6132 $oldtimeout = undef;
6138 print "restore vma archive: $dbg_cmdstring\n";
6139 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6143 alarm($oldtimeout) if $oldtimeout;
6146 foreach my $devname (keys %$devinfo) {
6147 my $volid = $devinfo->{$devname}->{volid
};
6148 push @$vollist, $volid if $volid;
6151 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6159 foreach my $devname (keys %$devinfo) {
6160 my $volid = $devinfo->{$devname}->{volid
};
6163 if ($volid =~ m
|^/|) {
6164 unlink $volid || die 'unlink failed\n';
6166 PVE
::Storage
::vdisk_free
($cfg, $volid);
6168 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6170 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6177 rename($tmpfn, $conffile) ||
6178 die "unable to commit configuration file '$conffile'\n";
6180 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6182 eval { rescan
($vmid, 1); };
6186 sub restore_tar_archive
{
6187 my ($archive, $vmid, $user, $opts) = @_;
6189 if ($archive ne '-') {
6190 my $firstfile = tar_archive_read_firstfile
($archive);
6191 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6192 if $firstfile ne 'qemu-server.conf';
6195 my $storecfg = PVE
::Storage
::config
();
6197 # destroy existing data - keep empty config
6198 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6199 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6201 my $tocmd = "/usr/lib/qemu-server/qmextract";
6203 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6204 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6205 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6206 $tocmd .= ' --info' if $opts->{info
};
6208 # tar option "xf" does not autodetect compression when read from STDIN,
6209 # so we pipe to zcat
6210 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6211 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6213 my $tmpdir = "/var/tmp/vzdumptmp$$";
6216 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6217 local $ENV{VZDUMP_VMID
} = $vmid;
6218 local $ENV{VZDUMP_USER
} = $user;
6220 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6221 my $tmpfn = "$conffile.$$.tmp";
6223 # disable interrupts (always do cleanups)
6227 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6235 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6237 if ($archive eq '-') {
6238 print "extracting archive from STDIN\n";
6239 run_command
($cmd, input
=> "<&STDIN");
6241 print "extracting archive '$archive'\n";
6245 return if $opts->{info
};
6249 my $statfile = "$tmpdir/qmrestore.stat";
6250 if (my $fd = IO
::File-
>new($statfile, "r")) {
6251 while (defined (my $line = <$fd>)) {
6252 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6253 $map->{$1} = $2 if $1;
6255 print STDERR
"unable to parse line in statfile - $line\n";
6261 my $confsrc = "$tmpdir/qemu-server.conf";
6263 my $srcfd = new IO
::File
($confsrc, "r") ||
6264 die "unable to open file '$confsrc'\n";
6266 my $outfd = new IO
::File
($tmpfn, "w") ||
6267 die "unable to write config for VM $vmid\n";
6269 my $cookie = { netcount
=> 0 };
6270 while (defined (my $line = <$srcfd>)) {
6271 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6283 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6290 rename $tmpfn, $conffile ||
6291 die "unable to commit configuration file '$conffile'\n";
6293 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6295 eval { rescan
($vmid, 1); };
6299 sub foreach_storage_used_by_vm
{
6300 my ($conf, $func) = @_;
6304 foreach_drive
($conf, sub {
6305 my ($ds, $drive) = @_;
6306 return if drive_is_cdrom
($drive);
6308 my $volid = $drive->{file
};
6310 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6311 $sidhash->{$sid} = $sid if $sid;
6314 foreach my $sid (sort keys %$sidhash) {
6319 sub do_snapshots_with_qemu
{
6320 my ($storecfg, $volid) = @_;
6322 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6324 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6325 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6329 if ($volid =~ m/\.(qcow2|qed)$/){
6336 sub qga_check_running
{
6337 my ($vmid, $nowarn) = @_;
6339 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6341 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6347 sub template_create
{
6348 my ($vmid, $conf, $disk) = @_;
6350 my $storecfg = PVE
::Storage
::config
();
6352 foreach_drive
($conf, sub {
6353 my ($ds, $drive) = @_;
6355 return if drive_is_cdrom
($drive);
6356 return if $disk && $ds ne $disk;
6358 my $volid = $drive->{file
};
6359 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6361 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6362 $drive->{file
} = $voliddst;
6363 $conf->{$ds} = print_drive
($vmid, $drive);
6364 PVE
::QemuConfig-
>write_config($vmid, $conf);
6368 sub qemu_img_convert
{
6369 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6371 my $storecfg = PVE
::Storage
::config
();
6372 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6373 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6375 if ($src_storeid && $dst_storeid) {
6377 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6379 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6380 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6382 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6383 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6385 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6386 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6389 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6390 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6391 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6392 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6393 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6394 if ($is_zero_initialized) {
6395 push @$cmd, "zeroinit:$dst_path";
6397 push @$cmd, $dst_path;
6402 if($line =~ m/\((\S+)\/100\
%\)/){
6404 my $transferred = int($size * $percent / 100);
6405 my $remaining = $size - $transferred;
6407 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6412 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6414 die "copy failed: $err" if $err;
6418 sub qemu_img_format
{
6419 my ($scfg, $volname) = @_;
6421 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6428 sub qemu_drive_mirror
{
6429 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6431 $jobs = {} if !$jobs;
6435 $jobs->{"drive-$drive"} = {};
6437 if ($dst_volid =~ /^nbd:/) {
6438 $qemu_target = $dst_volid;
6441 my $storecfg = PVE
::Storage
::config
();
6442 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6444 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6446 $format = qemu_img_format
($dst_scfg, $dst_volname);
6448 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6450 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6453 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6454 $opts->{format
} = $format if $format;
6456 print "drive mirror is starting for drive-$drive\n";
6458 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6461 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6462 die "mirroring error: $err";
6465 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6468 sub qemu_drive_mirror_monitor
{
6469 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6472 my $err_complete = 0;
6475 die "storage migration timed out\n" if $err_complete > 300;
6477 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6479 my $running_mirror_jobs = {};
6480 foreach my $stat (@$stats) {
6481 next if $stat->{type
} ne 'mirror';
6482 $running_mirror_jobs->{$stat->{device
}} = $stat;
6485 my $readycounter = 0;
6487 foreach my $job (keys %$jobs) {
6489 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6490 print "$job : finished\n";
6491 delete $jobs->{$job};
6495 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6497 my $busy = $running_mirror_jobs->{$job}->{busy
};
6498 my $ready = $running_mirror_jobs->{$job}->{ready
};
6499 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6500 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6501 my $remaining = $total - $transferred;
6502 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6504 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6507 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6510 last if scalar(keys %$jobs) == 0;
6512 if ($readycounter == scalar(keys %$jobs)) {
6513 print "all mirroring jobs are ready \n";
6514 last if $skipcomplete; #do the complete later
6516 if ($vmiddst && $vmiddst != $vmid) {
6517 my $agent_running = $qga && qga_check_running
($vmid);
6518 if ($agent_running) {
6519 print "freeze filesystem\n";
6520 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6522 print "suspend vm\n";
6523 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6526 # if we clone a disk for a new target vm, we don't switch the disk
6527 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6529 if ($agent_running) {
6530 print "unfreeze filesystem\n";
6531 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6533 print "resume vm\n";
6534 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6540 foreach my $job (keys %$jobs) {
6541 # try to switch the disk if source and destination are on the same guest
6542 print "$job: Completing block job...\n";
6544 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6545 if ($@ =~ m/cannot be completed/) {
6546 print "$job: Block job cannot be completed, try again.\n";
6549 print "$job: Completed successfully.\n";
6550 $jobs->{$job}->{complete
} = 1;
6561 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6562 die "mirroring error: $err";
6567 sub qemu_blockjobs_cancel
{
6568 my ($vmid, $jobs) = @_;
6570 foreach my $job (keys %$jobs) {
6571 print "$job: Cancelling block job\n";
6572 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6573 $jobs->{$job}->{cancel
} = 1;
6577 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6579 my $running_jobs = {};
6580 foreach my $stat (@$stats) {
6581 $running_jobs->{$stat->{device
}} = $stat;
6584 foreach my $job (keys %$jobs) {
6586 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6587 print "$job: Done.\n";
6588 delete $jobs->{$job};
6592 last if scalar(keys %$jobs) == 0;
6599 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6600 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6605 print "create linked clone of drive $drivename ($drive->{file})\n";
6606 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6607 push @$newvollist, $newvolid;
6610 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6611 $storeid = $storage if $storage;
6613 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6614 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6616 print "create full clone of drive $drivename ($drive->{file})\n";
6618 if (drive_is_cloudinit
($drive)) {
6619 $name = "vm-$newvmid-cloudinit";
6620 # cloudinit only supports raw and qcow2 atm:
6621 if ($dst_format eq 'qcow2') {
6623 } elsif ($dst_format ne 'raw') {
6624 die "clone: unhandled format for cloudinit image\n";
6627 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6628 push @$newvollist, $newvolid;
6630 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6632 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6633 if (!$running || $snapname) {
6634 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6637 my $kvmver = get_running_qemu_version
($vmid);
6638 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6639 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6640 if $drive->{iothread
};
6643 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6647 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6650 $disk->{format
} = undef;
6651 $disk->{file
} = $newvolid;
6652 $disk->{size
} = $size;
6657 # this only works if VM is running
6658 sub get_current_qemu_machine
{
6661 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6662 my $res = vm_qmp_command
($vmid, $cmd);
6664 my ($current, $default);
6665 foreach my $e (@$res) {
6666 $default = $e->{name
} if $e->{'is-default'};
6667 $current = $e->{name
} if $e->{'is-current'};
6670 # fallback to the default machine if current is not supported by qemu
6671 return $current || $default || 'pc';
6674 sub get_running_qemu_version
{
6676 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6677 my $res = vm_qmp_command
($vmid, $cmd);
6678 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6681 sub qemu_machine_feature_enabled
{
6682 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6687 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6689 $current_major = $3;
6690 $current_minor = $4;
6692 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6694 $current_major = $1;
6695 $current_minor = $2;
6698 return 1 if $current_major > $version_major ||
6699 ($current_major == $version_major &&
6700 $current_minor >= $version_minor);
6703 sub qemu_machine_pxe
{
6704 my ($vmid, $conf, $machine) = @_;
6706 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6708 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6715 sub qemu_use_old_bios_files
{
6716 my ($machine_type) = @_;
6718 return if !$machine_type;
6720 my $use_old_bios_files = undef;
6722 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6724 $use_old_bios_files = 1;
6726 my $kvmver = kvm_user_version
();
6727 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6728 # load new efi bios files on migration. So this hack is required to allow
6729 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6730 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6731 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6734 return ($use_old_bios_files, $machine_type);
6737 sub create_efidisk
($$$$$) {
6738 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6740 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6741 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6743 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6744 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6745 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6747 my $path = PVE
::Storage
::path
($storecfg, $volid);
6749 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6751 die "Copying EFI vars image failed: $@" if $@;
6753 return ($volid, $vars_size);
6756 sub vm_iothreads_list
{
6759 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6762 foreach my $iothread (@$res) {
6763 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6770 my ($conf, $drive) = @_;
6774 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6776 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6782 my $controller = int($drive->{index} / $maxdev);
6783 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6785 return ($maxdev, $controller, $controller_prefix);
6788 sub add_hyperv_enlightenments
{
6789 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6791 return if $winversion < 6;
6792 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6794 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6796 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6797 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6798 push @$cpuFlags , 'hv_vapic';
6799 push @$cpuFlags , 'hv_time';
6801 push @$cpuFlags , 'hv_spinlocks=0xffff';
6804 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6805 push @$cpuFlags , 'hv_reset';
6806 push @$cpuFlags , 'hv_vpindex';
6807 push @$cpuFlags , 'hv_runtime';
6810 if ($winversion >= 7) {
6811 push @$cpuFlags , 'hv_relaxed';
6813 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6814 push @$cpuFlags , 'hv_synic';
6815 push @$cpuFlags , 'hv_stimer';
6820 sub windows_version
{
6823 return 0 if !$ostype;
6827 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6829 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6831 } elsif ($ostype =~ m/^win(\d+)$/) {
6838 sub resolve_dst_disk_format
{
6839 my ($storecfg, $storeid, $src_volname, $format) = @_;
6840 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6843 # if no target format is specified, use the source disk format as hint
6845 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6846 $format = qemu_img_format
($scfg, $src_volname);
6852 # test if requested format is supported - else use default
6853 my $supported = grep { $_ eq $format } @$validFormats;
6854 $format = $defFormat if !$supported;
6858 sub resolve_first_disk
{
6860 my @disks = PVE
::QemuServer
::valid_drive_names
();
6862 foreach my $ds (reverse @disks) {
6863 next if !$conf->{$ds};
6864 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6865 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6872 my ($uuid, $uuid_str);
6873 UUID
::generate
($uuid);
6874 UUID
::unparse
($uuid, $uuid_str);
6878 sub generate_smbios1_uuid
{
6879 return "uuid=".generate_uuid
();
6885 vm_mon_cmd
($vmid, 'nbd-server-stop');
6888 # bash completion helper
6890 sub complete_backup_archives
{
6891 my ($cmdname, $pname, $cvalue) = @_;
6893 my $cfg = PVE
::Storage
::config
();
6897 if ($cvalue =~ m/^([^:]+):/) {
6901 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6904 foreach my $id (keys %$data) {
6905 foreach my $item (@{$data->{$id}}) {
6906 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6907 push @$res, $item->{volid
} if defined($item->{volid
});
6914 my $complete_vmid_full = sub {
6917 my $idlist = vmstatus
();
6921 foreach my $id (keys %$idlist) {
6922 my $d = $idlist->{$id};
6923 if (defined($running)) {
6924 next if $d->{template
};
6925 next if $running && $d->{status
} ne 'running';
6926 next if !$running && $d->{status
} eq 'running';
6935 return &$complete_vmid_full();
6938 sub complete_vmid_stopped
{
6939 return &$complete_vmid_full(0);
6942 sub complete_vmid_running
{
6943 return &$complete_vmid_full(1);
6946 sub complete_storage
{
6948 my $cfg = PVE
::Storage
::config
();
6949 my $ids = $cfg->{ids
};
6952 foreach my $sid (keys %$ids) {
6953 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6954 next if !$ids->{$sid}->{content
}->{images
};