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
;
38 use Time
::HiRes
qw(gettimeofday);
39 use File
::Copy
qw(copy);
42 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
45 "$EDK2_FW_BASE/OVMF_CODE.fd",
46 "$EDK2_FW_BASE/OVMF_VARS.fd"
49 "$EDK2_FW_BASE/AAVMF_CODE.fd",
50 "$EDK2_FW_BASE/AAVMF_VARS.fd"
54 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
56 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
58 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
60 # Note about locking: we use flock on the config file protect
61 # against concurent actions.
62 # Aditionaly, we have a 'lock' setting in the config file. This
63 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
64 # allowed when such lock is set. But you can ignore this kind of
65 # lock with the --skiplock flag.
67 cfs_register_file
('/qemu-server/',
71 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
72 description
=> "Some command save/restore state from this location.",
78 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
79 description
=> "The name of the snapshot.",
80 type
=> 'string', format
=> 'pve-configid',
84 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
86 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
87 description
=> "The drive's backing file's data format.",
91 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
92 description
=> "Specifies the Qemu machine type.",
94 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
99 #no warnings 'redefine';
102 my ($controller, $vmid, $option, $value) = @_;
104 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
105 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
109 my $nodename = PVE
::INotify
::nodename
();
111 mkdir "/etc/pve/nodes/$nodename";
112 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
115 my $var_run_tmpdir = "/var/run/qemu-server";
116 mkdir $var_run_tmpdir;
118 my $lock_dir = "/var/lock/qemu-server";
121 my $pcisysfs = "/sys/bus/pci";
123 my $cpu_vendor_list = {
125 486 => 'GenuineIntel',
126 pentium
=> 'GenuineIntel',
127 pentium2
=> 'GenuineIntel',
128 pentium3
=> 'GenuineIntel',
129 coreduo
=> 'GenuineIntel',
130 core2duo
=> 'GenuineIntel',
131 Conroe
=> 'GenuineIntel',
132 Penryn
=> 'GenuineIntel',
133 Nehalem
=> 'GenuineIntel',
134 'Nehalem-IBRS' => 'GenuineIntel',
135 Westmere
=> 'GenuineIntel',
136 'Westmere-IBRS' => 'GenuineIntel',
137 SandyBridge
=> 'GenuineIntel',
138 'SandyBridge-IBRS' => 'GenuineIntel',
139 IvyBridge
=> 'GenuineIntel',
140 'IvyBridge-IBRS' => 'GenuineIntel',
141 Haswell
=> 'GenuineIntel',
142 'Haswell-IBRS' => 'GenuineIntel',
143 'Haswell-noTSX' => 'GenuineIntel',
144 'Haswell-noTSX-IBRS' => 'GenuineIntel',
145 Broadwell
=> 'GenuineIntel',
146 'Broadwell-IBRS' => 'GenuineIntel',
147 'Broadwell-noTSX' => 'GenuineIntel',
148 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
149 'Skylake-Client' => 'GenuineIntel',
150 'Skylake-Client-IBRS' => 'GenuineIntel',
151 'Skylake-Server' => 'GenuineIntel',
152 'Skylake-Server-IBRS' => 'GenuineIntel',
155 athlon
=> 'AuthenticAMD',
156 phenom
=> 'AuthenticAMD',
157 Opteron_G1
=> 'AuthenticAMD',
158 Opteron_G2
=> 'AuthenticAMD',
159 Opteron_G3
=> 'AuthenticAMD',
160 Opteron_G4
=> 'AuthenticAMD',
161 Opteron_G5
=> 'AuthenticAMD',
162 EPYC
=> 'AuthenticAMD',
163 'EPYC-IBPB' => 'AuthenticAMD',
165 # generic types, use vendor from host node
174 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
178 description
=> "Emulated CPU type.",
180 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
185 description
=> "Do not identify as a KVM virtual machine.",
191 description
=> "List of additional CPU flags separated by ';'."
192 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
193 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
194 format_description
=> '+FLAG[;-FLAG...]',
196 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
205 enum
=> [qw(i6300esb ib700)],
206 description
=> "Watchdog type to emulate.",
207 default => 'i6300esb',
212 enum
=> [qw(reset shutdown poweroff pause debug none)],
213 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
217 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
221 description
=> "Enable/disable Qemu GuestAgent.",
226 fstrim_cloned_disks
=> {
227 description
=> "Run fstrim after cloning/moving a disk.",
236 description
=> "Select the VGA type.",
241 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 serial0 serial1 serial2 serial3 std virtio vmware)],
244 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
256 description
=> "Specifies whether a VM will be started during system bootup.",
262 description
=> "Automatic restart after crash (currently ignored).",
267 type
=> 'string', format
=> 'pve-hotplug-features',
268 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'.",
269 default => 'network,disk,usb',
274 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
280 description
=> "Lock/unlock the VM.",
281 enum
=> [qw(migrate backup snapshot rollback)],
286 description
=> "Limit of CPU usage.",
287 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.",
295 description
=> "CPU weight for a VM.",
296 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.",
304 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
311 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
317 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.",
325 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
326 "It should not be necessary to set it.",
327 enum
=> PVE
::Tools
::kvmkeymaplist
(),
332 type
=> 'string', format
=> 'dns-name',
333 description
=> "Set a name for the VM. Only used on the configuration web interface.",
338 description
=> "SCSI controller model",
339 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
345 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
350 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
351 description
=> "Specify guest operating system.",
352 verbose_description
=> <<EODESC,
353 Specify guest operating system. This is used to enable special
354 optimization/features for specific operating systems:
357 other;; unspecified OS
358 wxp;; Microsoft Windows XP
359 w2k;; Microsoft Windows 2000
360 w2k3;; Microsoft Windows 2003
361 w2k8;; Microsoft Windows 2008
362 wvista;; Microsoft Windows Vista
363 win7;; Microsoft Windows 7
364 win8;; Microsoft Windows 8/2012/2012r2
365 win10;; Microsoft Windows 10/2016
366 l24;; Linux 2.4 Kernel
367 l26;; Linux 2.6/3.X Kernel
368 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
374 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
375 pattern
=> '[acdn]{1,4}',
380 type
=> 'string', format
=> 'pve-qm-bootdisk',
381 description
=> "Enable booting from specified disk.",
382 pattern
=> '(ide|sata|scsi|virtio)\d+',
387 description
=> "The number of CPUs. Please use option -sockets instead.",
394 description
=> "The number of CPU sockets.",
401 description
=> "The number of cores per socket.",
408 description
=> "Enable/disable NUMA.",
414 description
=> "Enable/disable hugepages memory.",
415 enum
=> [qw(any 2 1024)],
420 description
=> "Number of hotplugged vcpus.",
427 description
=> "Enable/disable ACPI.",
432 description
=> "Enable/disable Qemu GuestAgent and its properties.",
434 format
=> $agent_fmt,
439 description
=> "Enable/disable KVM hardware virtualization.",
445 description
=> "Enable/disable time drift fix.",
451 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
456 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
460 type
=> 'string', format
=> $vga_fmt,
461 description
=> "Configure the VGA hardware.",
462 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
463 "high resolution modes (>= 1280x1024x16) you may need to increase " .
464 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
465 "is 'std' for all OS types besides some Windows versions (XP and " .
466 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
467 "display server. For win* OS you can select how many independent " .
468 "displays you want, Linux guests can add displays them self.\n".
469 "You can also run without any graphic card, using a serial device as terminal.",
473 type
=> 'string', format
=> 'pve-qm-watchdog',
474 description
=> "Create a virtual hardware watchdog device.",
475 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
476 " (by a guest action), the watchdog must be periodically polled " .
477 "by an agent inside the guest or else the watchdog will reset " .
478 "the guest (or execute the respective action specified)",
483 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
484 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'.",
485 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
488 startup
=> get_standard_option
('pve-startup-order'),
492 description
=> "Enable/disable Template.",
498 description
=> "Arbitrary arguments passed to kvm.",
499 verbose_description
=> <<EODESCR,
500 Arbitrary arguments passed to kvm, for example:
502 args: -no-reboot -no-hpet
504 NOTE: this option is for experts only.
511 description
=> "Enable/disable the USB tablet device.",
512 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
513 "usually needed to allow absolute mouse positioning with VNC. " .
514 "Else the mouse runs out of sync with normal VNC clients. " .
515 "If you're running lots of console-only guests on one host, " .
516 "you may consider disabling this to save some context switches. " .
517 "This is turned off by default if you use spice (-vga=qxl).",
522 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
526 migrate_downtime
=> {
529 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
535 type
=> 'string', format
=> 'pve-qm-ide',
536 typetext
=> '<volume>',
537 description
=> "This is an alias for option -ide2",
541 description
=> "Emulated CPU type.",
545 parent
=> get_standard_option
('pve-snapshot-name', {
547 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
551 description
=> "Timestamp for snapshots.",
557 type
=> 'string', format
=> 'pve-volume-id',
558 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
560 vmstatestorage
=> get_standard_option
('pve-storage-id', {
561 description
=> "Default storage for VM state volumes/files.",
564 runningmachine
=> get_standard_option
('pve-qemu-machine', {
565 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
567 machine
=> get_standard_option
('pve-qemu-machine'),
569 description
=> "Virtual processor architecture. Defaults to the host.",
572 enum
=> [qw(x86_64 aarch64)],
575 description
=> "Specify SMBIOS type 1 fields.",
576 type
=> 'string', format
=> 'pve-qm-smbios1',
583 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
589 enum
=> [ qw(seabios ovmf) ],
590 description
=> "Select BIOS implementation.",
591 default => 'seabios',
595 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
596 format_description
=> 'UUID',
597 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
598 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
599 " 128-bit integer value identifier to the guest OS. This allows to".
600 " notify the guest operating system when the virtual machine is".
601 " executed with a different configuration (e.g. snapshot execution".
602 " or creation from a template). The guest operating system notices".
603 " the change, and is then able to react as appropriate by marking".
604 " its copies of distributed databases as dirty, re-initializing its".
605 " random number generator, etc.\n".
606 "Note that auto-creation only works when done throug API/CLI create".
607 " or update methods, but not when manually editing the config file.",
608 default => "1 (autogenerated)",
613 my $confdesc_cloudinit = {
617 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.',
618 enum
=> ['configdrive2', 'nocloud'],
623 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
628 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.',
633 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.",
637 type
=> 'string', format
=> 'address-list',
638 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.",
643 format
=> 'urlencoded',
644 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
648 # what about other qemu settings ?
650 #machine => 'string',
663 ##soundhw => 'string',
665 while (my ($k, $v) = each %$confdesc) {
666 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
669 my $MAX_IDE_DISKS = 4;
670 my $MAX_SCSI_DISKS = 14;
671 my $MAX_VIRTIO_DISKS = 16;
672 my $MAX_SATA_DISKS = 6;
673 my $MAX_USB_DEVICES = 5;
675 my $MAX_UNUSED_DISKS = 256;
676 my $MAX_HOSTPCI_DEVICES = 4;
677 my $MAX_SERIAL_PORTS = 4;
678 my $MAX_PARALLEL_PORTS = 3;
684 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
685 description
=> "CPUs accessing this NUMA node.",
686 format_description
=> "id[-id];...",
690 description
=> "Amount of memory this NUMA node provides.",
695 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
696 description
=> "Host NUMA nodes to use.",
697 format_description
=> "id[-id];...",
702 enum
=> [qw(preferred bind interleave)],
703 description
=> "NUMA allocation policy.",
707 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
710 type
=> 'string', format
=> $numa_fmt,
711 description
=> "NUMA topology.",
713 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
715 for (my $i = 0; $i < $MAX_NUMA; $i++) {
716 $confdesc->{"numa$i"} = $numadesc;
719 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
720 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
721 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
722 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
724 my $net_fmt_bridge_descr = <<__EOD__;
725 Bridge to attach the network device to. The Proxmox VE standard bridge
728 If you do not specify a bridge, we create a kvm user (NATed) network
729 device, which provides DHCP and DNS services. The following addresses
736 The DHCP server assign addresses to the guest starting from 10.0.2.15.
742 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
743 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
744 format_description
=> "XX:XX:XX:XX:XX:XX",
749 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'.",
750 enum
=> $nic_model_list,
753 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
756 description
=> $net_fmt_bridge_descr,
757 format_description
=> 'bridge',
762 minimum
=> 0, maximum
=> 16,
763 description
=> 'Number of packet queues to be used on the device.',
769 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
774 minimum
=> 1, maximum
=> 4094,
775 description
=> 'VLAN tag to apply to packets on this interface.',
780 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
781 description
=> 'VLAN trunks to pass through this interface.',
782 format_description
=> 'vlanid[;vlanid...]',
787 description
=> 'Whether this interface should be protected by the firewall.',
792 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
799 type
=> 'string', format
=> $net_fmt,
800 description
=> "Specify network devices.",
803 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
808 format
=> 'pve-ipv4-config',
809 format_description
=> 'IPv4Format/CIDR',
810 description
=> 'IPv4 address in CIDR format.',
817 format_description
=> 'GatewayIPv4',
818 description
=> 'Default gateway for IPv4 traffic.',
824 format
=> 'pve-ipv6-config',
825 format_description
=> 'IPv6Format/CIDR',
826 description
=> 'IPv6 address in CIDR format.',
833 format_description
=> 'GatewayIPv6',
834 description
=> 'Default gateway for IPv6 traffic.',
839 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
842 type
=> 'string', format
=> 'pve-qm-ipconfig',
843 description
=> <<'EODESCR',
844 cloud-init: Specify IP addresses and gateways for the corresponding interface.
846 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
848 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
849 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
851 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
854 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
856 for (my $i = 0; $i < $MAX_NETS; $i++) {
857 $confdesc->{"net$i"} = $netdesc;
858 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
861 foreach my $key (keys %$confdesc_cloudinit) {
862 $confdesc->{$key} = $confdesc_cloudinit->{$key};
865 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
866 sub verify_volume_id_or_qm_path
{
867 my ($volid, $noerr) = @_;
869 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
873 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
874 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
876 return undef if $noerr;
884 my %drivedesc_base = (
885 volume
=> { alias
=> 'file' },
888 format
=> 'pve-volume-id-or-qm-path',
890 format_description
=> 'volume',
891 description
=> "The drive's backing volume.",
895 enum
=> [qw(cdrom disk)],
896 description
=> "The drive's media type.",
902 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
907 description
=> "Force the drive's physical geometry to have a specific head count.",
912 description
=> "Force the drive's physical geometry to have a specific sector count.",
917 enum
=> [qw(none lba auto)],
918 description
=> "Force disk geometry bios translation mode.",
923 description
=> "Controls qemu's snapshot mode feature."
924 . " If activated, changes made to the disk are temporary and will"
925 . " be discarded when the VM is shutdown.",
930 enum
=> [qw(none writethrough writeback unsafe directsync)],
931 description
=> "The drive's cache mode",
934 format
=> get_standard_option
('pve-qm-image-format'),
937 format
=> 'disk-size',
938 format_description
=> 'DiskSize',
939 description
=> "Disk size. This is purely informational and has no effect.",
944 description
=> "Whether the drive should be included when making backups.",
949 description
=> 'Whether the drive should considered for replication jobs.',
955 enum
=> [qw(ignore report stop)],
956 description
=> 'Read error action.',
961 enum
=> [qw(enospc ignore report stop)],
962 description
=> 'Write error action.',
967 enum
=> [qw(native threads)],
968 description
=> 'AIO type to use.',
973 enum
=> [qw(ignore on)],
974 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
979 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
984 format
=> 'urlencoded',
985 format_description
=> 'serial',
986 maxLength
=> 20*3, # *3 since it's %xx url enoded
987 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
992 description
=> 'Mark this locally-managed volume as available on all nodes',
993 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!",
999 my %iothread_fmt = ( iothread
=> {
1001 description
=> "Whether to use iothreads for this drive",
1008 format
=> 'urlencoded',
1009 format_description
=> 'model',
1010 maxLength
=> 40*3, # *3 since it's %xx url enoded
1011 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1019 description
=> "Number of queues.",
1025 my %scsiblock_fmt = (
1028 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",
1037 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1042 my $add_throttle_desc = sub {
1043 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1046 format_description
=> $unit,
1047 description
=> "Maximum $what in $longunit.",
1050 $d->{minimum
} = $minimum if defined($minimum);
1051 $drivedesc_base{$key} = $d;
1053 # throughput: (leaky bucket)
1054 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1055 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1056 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1057 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1058 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1059 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1060 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1061 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1062 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1064 # pools: (pool of IO before throttling starts taking effect)
1065 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1066 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1067 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1068 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1069 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1070 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1073 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1074 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1075 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1076 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1077 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1078 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1081 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1082 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1083 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1084 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1091 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1095 type
=> 'string', format
=> $ide_fmt,
1096 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1098 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1109 type
=> 'string', format
=> $scsi_fmt,
1110 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1112 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1120 type
=> 'string', format
=> $sata_fmt,
1121 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1123 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1131 type
=> 'string', format
=> $virtio_fmt,
1132 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1134 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1136 my $alldrive_fmt = {
1146 volume
=> { alias
=> 'file' },
1149 format
=> 'pve-volume-id-or-qm-path',
1151 format_description
=> 'volume',
1152 description
=> "The drive's backing volume.",
1154 format
=> get_standard_option
('pve-qm-image-format'),
1157 format
=> 'disk-size',
1158 format_description
=> 'DiskSize',
1159 description
=> "Disk size. This is purely informational and has no effect.",
1164 my $efidisk_desc = {
1166 type
=> 'string', format
=> $efidisk_fmt,
1167 description
=> "Configure a Disk for storing EFI vars",
1170 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1175 type
=> 'string', format
=> 'pve-qm-usb-device',
1176 format_description
=> 'HOSTUSBDEVICE|spice',
1177 description
=> <<EODESCR,
1178 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1180 'bus-port(.port)*' (decimal numbers) or
1181 'vendor_id:product_id' (hexadeciaml numbers) or
1184 You can use the 'lsusb -t' command to list existing usb devices.
1186 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1188 The value 'spice' can be used to add a usb redirection devices for spice.
1194 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).",
1201 type
=> 'string', format
=> $usb_fmt,
1202 description
=> "Configure an USB device (n is 0 to 4).",
1204 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1206 # NOTE: the match-groups of this regex are used in parse_hostpci
1207 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1212 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1213 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1214 description
=> <<EODESCR,
1215 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1216 of PCI virtual functions of the host. HOSTPCIID syntax is:
1218 'bus:dev.func' (hexadecimal numbers)
1220 You can us the 'lspci' command to list existing PCI devices.
1225 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1231 pattern
=> '[^,;]+',
1232 format_description
=> 'string',
1233 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1238 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1244 description
=> "Enable vfio-vga device support.",
1249 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1253 type
=> 'string', format
=> 'pve-qm-hostpci',
1254 description
=> "Map host PCI devices into guest.",
1255 verbose_description
=> <<EODESCR,
1256 Map host PCI devices into guest.
1258 NOTE: This option allows direct access to host hardware. So it is no longer
1259 possible to migrate such machines - use with special care.
1261 CAUTION: Experimental! User reported problems with this option.
1264 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1269 pattern
=> '(/dev/.+|socket)',
1270 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1271 verbose_description
=> <<EODESCR,
1272 Create a serial device inside the VM (n is 0 to 3), and pass through a
1273 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1274 host side (use 'qm terminal' to open a terminal connection).
1276 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1278 CAUTION: Experimental! User reported problems with this option.
1285 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1286 description
=> "Map host parallel devices (n is 0 to 2).",
1287 verbose_description
=> <<EODESCR,
1288 Map host parallel devices (n is 0 to 2).
1290 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1292 CAUTION: Experimental! User reported problems with this option.
1296 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1297 $confdesc->{"parallel$i"} = $paralleldesc;
1300 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1301 $confdesc->{"serial$i"} = $serialdesc;
1304 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1305 $confdesc->{"hostpci$i"} = $hostpcidesc;
1308 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1309 $drivename_hash->{"ide$i"} = 1;
1310 $confdesc->{"ide$i"} = $idedesc;
1313 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1314 $drivename_hash->{"sata$i"} = 1;
1315 $confdesc->{"sata$i"} = $satadesc;
1318 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1319 $drivename_hash->{"scsi$i"} = 1;
1320 $confdesc->{"scsi$i"} = $scsidesc ;
1323 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1324 $drivename_hash->{"virtio$i"} = 1;
1325 $confdesc->{"virtio$i"} = $virtiodesc;
1328 $drivename_hash->{efidisk0
} = 1;
1329 $confdesc->{efidisk0
} = $efidisk_desc;
1331 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1332 $confdesc->{"usb$i"} = $usbdesc;
1337 type
=> 'string', format
=> 'pve-volume-id',
1338 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1341 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1342 $confdesc->{"unused$i"} = $unuseddesc;
1345 my $kvm_api_version = 0;
1348 return $kvm_api_version if $kvm_api_version;
1350 open my $fh, '<', '/dev/kvm'
1353 # 0xae00 => KVM_GET_API_VERSION
1354 $kvm_api_version = ioctl($fh, 0xae00, 0);
1356 return $kvm_api_version;
1359 my $kvm_user_version;
1361 sub kvm_user_version
{
1363 return $kvm_user_version if $kvm_user_version;
1365 $kvm_user_version = 'unknown';
1369 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1370 $kvm_user_version = $2;
1374 eval { run_command
("kvm -version", outfunc
=> $code); };
1377 return $kvm_user_version;
1381 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1383 sub valid_drive_names
{
1384 # order is important - used to autoselect boot disk
1385 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1386 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1387 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1388 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1392 sub is_valid_drivename
{
1395 return defined($drivename_hash->{$dev});
1400 return defined($confdesc->{$key});
1404 return $nic_model_list;
1407 sub os_list_description
{
1411 wxp
=> 'Windows XP',
1412 w2k
=> 'Windows 2000',
1413 w2k3
=>, 'Windows 2003',
1414 w2k8
=> 'Windows 2008',
1415 wvista
=> 'Windows Vista',
1416 win7
=> 'Windows 7',
1417 win8
=> 'Windows 8/2012',
1418 win10
=> 'Windows 10/2016',
1426 sub get_cdrom_path
{
1428 return $cdrom_path if $cdrom_path;
1430 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1431 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1432 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1436 my ($storecfg, $vmid, $cdrom) = @_;
1438 if ($cdrom eq 'cdrom') {
1439 return get_cdrom_path
();
1440 } elsif ($cdrom eq 'none') {
1442 } elsif ($cdrom =~ m
|^/|) {
1445 return PVE
::Storage
::path
($storecfg, $cdrom);
1449 # try to convert old style file names to volume IDs
1450 sub filename_to_volume_id
{
1451 my ($vmid, $file, $media) = @_;
1453 if (!($file eq 'none' || $file eq 'cdrom' ||
1454 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1456 return undef if $file =~ m
|/|;
1458 if ($media && $media eq 'cdrom') {
1459 $file = "local:iso/$file";
1461 $file = "local:$vmid/$file";
1468 sub verify_media_type
{
1469 my ($opt, $vtype, $media) = @_;
1474 if ($media eq 'disk') {
1476 } elsif ($media eq 'cdrom') {
1479 die "internal error";
1482 return if ($vtype eq $etype);
1484 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1487 sub cleanup_drive_path
{
1488 my ($opt, $storecfg, $drive) = @_;
1490 # try to convert filesystem paths to volume IDs
1492 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1493 ($drive->{file
} !~ m
|^/dev/.+|) &&
1494 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1495 ($drive->{file
} !~ m/^\d+$/)) {
1496 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1497 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1498 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1499 verify_media_type
($opt, $vtype, $drive->{media
});
1500 $drive->{file
} = $volid;
1503 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1506 sub parse_hotplug_features
{
1511 return $res if $data eq '0';
1513 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1515 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1516 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1519 die "invalid hotplug feature '$feature'\n";
1525 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1526 sub pve_verify_hotplug_features
{
1527 my ($value, $noerr) = @_;
1529 return $value if parse_hotplug_features
($value);
1531 return undef if $noerr;
1533 die "unable to parse hotplug option\n";
1536 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1537 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1538 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1539 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1540 # [,iothread=on][,serial=serial][,model=model]
1543 my ($key, $data) = @_;
1545 my ($interface, $index);
1547 if ($key =~ m/^([^\d]+)(\d+)$/) {
1554 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1555 : $confdesc->{$key}->{format
};
1557 warn "invalid drive key: $key\n";
1560 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1561 return undef if !$res;
1562 $res->{interface
} = $interface;
1563 $res->{index} = $index;
1566 foreach my $opt (qw(bps bps_rd bps_wr)) {
1567 if (my $bps = defined(delete $res->{$opt})) {
1568 if (defined($res->{"m$opt"})) {
1569 warn "both $opt and m$opt specified\n";
1573 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1577 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1578 for my $requirement (
1579 [mbps_max
=> 'mbps'],
1580 [mbps_rd_max
=> 'mbps_rd'],
1581 [mbps_wr_max
=> 'mbps_wr'],
1582 [miops_max
=> 'miops'],
1583 [miops_rd_max
=> 'miops_rd'],
1584 [miops_wr_max
=> 'miops_wr'],
1585 [bps_max_length
=> 'mbps_max'],
1586 [bps_rd_max_length
=> 'mbps_rd_max'],
1587 [bps_wr_max_length
=> 'mbps_wr_max'],
1588 [iops_max_length
=> 'iops_max'],
1589 [iops_rd_max_length
=> 'iops_rd_max'],
1590 [iops_wr_max_length
=> 'iops_wr_max']) {
1591 my ($option, $requires) = @$requirement;
1592 if ($res->{$option} && !$res->{$requires}) {
1593 warn "$option requires $requires\n";
1598 return undef if $error;
1600 return undef if $res->{mbps_rd
} && $res->{mbps
};
1601 return undef if $res->{mbps_wr
} && $res->{mbps
};
1602 return undef if $res->{iops_rd
} && $res->{iops
};
1603 return undef if $res->{iops_wr
} && $res->{iops
};
1605 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1606 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1607 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1608 return undef if $res->{interface
} eq 'virtio';
1611 if (my $size = $res->{size
}) {
1612 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1619 my ($vmid, $drive) = @_;
1620 my $data = { %$drive };
1621 delete $data->{$_} for qw(index interface);
1622 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1626 my($fh, $noerr) = @_;
1629 my $SG_GET_VERSION_NUM = 0x2282;
1631 my $versionbuf = "\x00" x
8;
1632 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1634 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1637 my $version = unpack("I", $versionbuf);
1638 if ($version < 30000) {
1639 die "scsi generic interface too old\n" if !$noerr;
1643 my $buf = "\x00" x
36;
1644 my $sensebuf = "\x00" x
8;
1645 my $cmd = pack("C x3 C x1", 0x12, 36);
1647 # see /usr/include/scsi/sg.h
1648 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";
1650 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1651 length($sensebuf), 0, length($buf), $buf,
1652 $cmd, $sensebuf, 6000);
1654 $ret = ioctl($fh, $SG_IO, $packet);
1656 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1660 my @res = unpack($sg_io_hdr_t, $packet);
1661 if ($res[17] || $res[18]) {
1662 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1667 (my $byte0, my $byte1, $res->{vendor
},
1668 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1670 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1671 $res->{type
} = $byte0 & 31;
1679 my $fh = IO
::File-
>new("+<$path") || return undef;
1680 my $res = scsi_inquiry
($fh, 1);
1686 sub machine_type_is_q35
{
1689 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1692 sub print_tabletdevice_full
{
1695 my $q35 = machine_type_is_q35
($conf);
1697 # we use uhci for old VMs because tablet driver was buggy in older qemu
1698 my $usbbus = $q35 ?
"ehci" : "uhci";
1700 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1703 sub print_drivedevice_full
{
1704 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1709 if ($drive->{interface
} eq 'virtio') {
1710 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1711 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1712 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1713 } elsif ($drive->{interface
} eq 'scsi') {
1715 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1716 my $unit = $drive->{index} % $maxdev;
1717 my $devicetype = 'hd';
1719 if (drive_is_cdrom
($drive)) {
1722 if ($drive->{file
} =~ m
|^/|) {
1723 $path = $drive->{file
};
1724 if (my $info = path_is_scsi
($path)) {
1725 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1726 $devicetype = 'block';
1727 } elsif ($info->{type
} == 1) { # tape
1728 $devicetype = 'generic';
1732 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1735 if($path =~ m/^iscsi\:\/\
//){
1736 $devicetype = 'generic';
1740 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1741 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1743 $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}";
1746 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1747 $device .= ",rotation_rate=1";
1750 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1751 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1752 my $controller = int($drive->{index} / $maxdev);
1753 my $unit = $drive->{index} % $maxdev;
1754 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1756 $device = "ide-$devicetype";
1757 if ($drive->{interface
} eq 'ide') {
1758 $device .= ",bus=ide.$controller,unit=$unit";
1760 $device .= ",bus=ahci$controller.$unit";
1762 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1764 if ($devicetype eq 'hd') {
1765 if (my $model = $drive->{model
}) {
1766 $model = URI
::Escape
::uri_unescape
($model);
1767 $device .= ",model=$model";
1769 if ($drive->{ssd
}) {
1770 $device .= ",rotation_rate=1";
1773 } elsif ($drive->{interface
} eq 'usb') {
1775 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1777 die "unsupported interface type";
1780 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1782 if (my $serial = $drive->{serial
}) {
1783 $serial = URI
::Escape
::uri_unescape
($serial);
1784 $device .= ",serial=$serial";
1791 sub get_initiator_name
{
1794 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1795 while (defined(my $line = <$fh>)) {
1796 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1805 sub print_drive_full
{
1806 my ($storecfg, $vmid, $drive) = @_;
1809 my $volid = $drive->{file
};
1812 if (drive_is_cdrom
($drive)) {
1813 $path = get_iso_path
($storecfg, $vmid, $volid);
1815 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1817 $path = PVE
::Storage
::path
($storecfg, $volid);
1818 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1819 $format = qemu_img_format
($scfg, $volname);
1827 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1828 foreach my $o (@qemu_drive_options) {
1829 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1832 # snapshot only accepts on|off
1833 if (defined($drive->{snapshot
})) {
1834 my $v = $drive->{snapshot
} ?
'on' : 'off';
1835 $opts .= ",snapshot=$v";
1838 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1839 my ($dir, $qmpname) = @$type;
1840 if (my $v = $drive->{"mbps$dir"}) {
1841 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1843 if (my $v = $drive->{"mbps${dir}_max"}) {
1844 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1846 if (my $v = $drive->{"bps${dir}_max_length"}) {
1847 $opts .= ",throttling.bps$qmpname-max-length=$v";
1849 if (my $v = $drive->{"iops${dir}"}) {
1850 $opts .= ",throttling.iops$qmpname=$v";
1852 if (my $v = $drive->{"iops${dir}_max"}) {
1853 $opts .= ",throttling.iops$qmpname-max=$v";
1855 if (my $v = $drive->{"iops${dir}_max_length"}) {
1856 $opts .= ",throttling.iops$qmpname-max-length=$v";
1860 $opts .= ",format=$format" if $format && !$drive->{format
};
1862 my $cache_direct = 0;
1864 if (my $cache = $drive->{cache
}) {
1865 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1866 } elsif (!drive_is_cdrom
($drive)) {
1867 $opts .= ",cache=none";
1871 # aio native works only with O_DIRECT
1872 if (!$drive->{aio
}) {
1874 $opts .= ",aio=native";
1876 $opts .= ",aio=threads";
1880 if (!drive_is_cdrom
($drive)) {
1882 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1883 $detectzeroes = 'off';
1884 } elsif ($drive->{discard
}) {
1885 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1887 # This used to be our default with discard not being specified:
1888 $detectzeroes = 'on';
1890 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1893 my $pathinfo = $path ?
"file=$path," : '';
1895 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1898 sub print_netdevice_full
{
1899 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1901 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1903 my $device = $net->{model
};
1904 if ($net->{model
} eq 'virtio') {
1905 $device = 'virtio-net-pci';
1908 my $pciaddr = print_pci_addr
("$netid", $bridges);
1909 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1910 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1911 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1912 my $vectors = $net->{queues
} * 2 + 2;
1913 $tmpstr .= ",vectors=$vectors,mq=on";
1915 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1917 if ($use_old_bios_files) {
1919 if ($device eq 'virtio-net-pci') {
1920 $romfile = 'pxe-virtio.rom';
1921 } elsif ($device eq 'e1000') {
1922 $romfile = 'pxe-e1000.rom';
1923 } elsif ($device eq 'ne2k') {
1924 $romfile = 'pxe-ne2k_pci.rom';
1925 } elsif ($device eq 'pcnet') {
1926 $romfile = 'pxe-pcnet.rom';
1927 } elsif ($device eq 'rtl8139') {
1928 $romfile = 'pxe-rtl8139.rom';
1930 $tmpstr .= ",romfile=$romfile" if $romfile;
1936 sub print_netdev_full
{
1937 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1940 if ($netid =~ m/^net(\d+)$/) {
1944 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1946 my $ifname = "tap${vmid}i$i";
1948 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1949 die "interface name '$ifname' is too long (max 15 character)\n"
1950 if length($ifname) >= 16;
1952 my $vhostparam = '';
1953 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1955 my $vmname = $conf->{name
} || "vm$vmid";
1958 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1960 if ($net->{bridge
}) {
1961 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1963 $netdev = "type=user,id=$netid,hostname=$vmname";
1966 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1972 sub print_cpu_device
{
1973 my ($conf, $id) = @_;
1975 my $kvm = $conf->{kvm
} // 1;
1976 my $cpu = $kvm ?
"kvm64" : "qemu64";
1977 if (my $cputype = $conf->{cpu
}) {
1978 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1979 or die "Cannot parse cpu description: $cputype\n";
1980 $cpu = $cpuconf->{cputype
};
1983 my $cores = $conf->{cores
} || 1;
1985 my $current_core = ($id - 1) % $cores;
1986 my $current_socket = int(($id - 1 - $current_core)/$cores);
1988 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1992 'cirrus' => 'cirrus-vga',
1994 'vmware' => 'vmware-svga',
1995 'virtio' => 'virtio-vga',
1998 sub print_vga_device
{
1999 my ($conf, $vga, $id, $qxlnum, $bridges) = @_;
2001 my $type = $vga_map->{$vga->{type
}};
2002 my $vgamem_mb = $vga->{memory
};
2004 $type = $id ?
'qxl' : 'qxl-vga';
2006 die "no devicetype for $vga->{type}\n" if !$type;
2010 if ($vga->{type
} eq 'virtio') {
2011 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2012 $memory = ",max_hostmem=$bytes";
2014 # from https://www.spice-space.org/multiple-monitors.html
2015 $memory = ",vgamem_mb=$vga->{memory}";
2016 my $ram = $vgamem_mb * 4;
2017 my $vram = $vgamem_mb * 2;
2018 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2020 $memory = ",vgamem_mb=$vga->{memory}";
2022 } elsif ($qxlnum && $id) {
2023 $memory = ",ram_size=67108864,vram_size=33554432";
2026 my $q35 = machine_type_is_q35
($conf);
2027 my $vgaid = "vga" . ($id // '');
2030 if ($q35 && $vgaid eq 'vga') {
2031 # the first display uses pcie.0 bus on q35 machines
2032 $pciaddr = print_pcie_addr
($vgaid, $bridges);
2034 $pciaddr = print_pci_addr
($vgaid, $bridges);
2037 return "$type,id=${vgaid}${memory}${pciaddr}";
2040 sub drive_is_cloudinit
{
2042 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2045 sub drive_is_cdrom
{
2046 my ($drive, $exclude_cloudinit) = @_;
2048 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2050 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2054 sub parse_number_sets
{
2057 foreach my $part (split(/;/, $set)) {
2058 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2059 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2060 push @$res, [ $1, $2 ];
2062 die "invalid range: $part\n";
2071 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2072 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2073 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2080 return undef if !$value;
2082 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2084 my @idlist = split(/;/, $res->{host
});
2085 delete $res->{host
};
2086 foreach my $id (@idlist) {
2087 if ($id =~ /^$PCIRE$/) {
2089 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
2091 my $pcidevices = lspci
($1);
2092 $res->{pciid
} = $pcidevices->{$1};
2095 # should have been caught by parse_property_string already
2096 die "failed to parse PCI id: $id\n";
2102 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2106 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2111 if (!defined($res->{macaddr
})) {
2112 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2113 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2118 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2119 sub parse_ipconfig
{
2122 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2128 if ($res->{gw
} && !$res->{ip
}) {
2129 warn 'gateway specified without specifying an IP address';
2132 if ($res->{gw6
} && !$res->{ip6
}) {
2133 warn 'IPv6 gateway specified without specifying an IPv6 address';
2136 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2137 warn 'gateway specified together with DHCP';
2140 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2142 warn "IPv6 gateway specified together with $res->{ip6} address";
2146 if (!$res->{ip
} && !$res->{ip6
}) {
2147 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2156 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2159 sub add_random_macs
{
2160 my ($settings) = @_;
2162 foreach my $opt (keys %$settings) {
2163 next if $opt !~ m/^net(\d+)$/;
2164 my $net = parse_net
($settings->{$opt});
2166 $settings->{$opt} = print_net
($net);
2170 sub vm_is_volid_owner
{
2171 my ($storecfg, $vmid, $volid) = @_;
2173 if ($volid !~ m
|^/|) {
2175 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2176 if ($owner && ($owner == $vmid)) {
2184 sub split_flagged_list
{
2185 my $text = shift || '';
2186 $text =~ s/[,;]/ /g;
2188 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2191 sub join_flagged_list
{
2192 my ($how, $lst) = @_;
2193 join $how, map { $lst->{$_} . $_ } keys %$lst;
2196 sub vmconfig_delete_pending_option
{
2197 my ($conf, $key, $force) = @_;
2199 delete $conf->{pending
}->{$key};
2200 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2201 $pending_delete_hash->{$key} = $force ?
'!' : '';
2202 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2205 sub vmconfig_undelete_pending_option
{
2206 my ($conf, $key) = @_;
2208 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2209 delete $pending_delete_hash->{$key};
2211 if (%$pending_delete_hash) {
2212 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2214 delete $conf->{pending
}->{delete};
2218 sub vmconfig_register_unused_drive
{
2219 my ($storecfg, $vmid, $conf, $drive) = @_;
2221 if (drive_is_cloudinit
($drive)) {
2222 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2224 } elsif (!drive_is_cdrom
($drive)) {
2225 my $volid = $drive->{file
};
2226 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2227 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2232 sub vmconfig_cleanup_pending
{
2235 # remove pending changes when nothing changed
2237 foreach my $opt (keys %{$conf->{pending
}}) {
2238 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2240 delete $conf->{pending
}->{$opt};
2244 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2245 my $pending_delete_hash = {};
2246 while (my ($opt, $force) = each %$current_delete_hash) {
2247 if (defined($conf->{$opt})) {
2248 $pending_delete_hash->{$opt} = $force;
2254 if (%$pending_delete_hash) {
2255 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2257 delete $conf->{pending
}->{delete};
2263 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2267 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2268 format_description
=> 'UUID',
2269 description
=> "Set SMBIOS1 UUID.",
2275 format_description
=> 'string',
2276 description
=> "Set SMBIOS1 version.",
2282 format_description
=> 'string',
2283 description
=> "Set SMBIOS1 serial number.",
2289 format_description
=> 'string',
2290 description
=> "Set SMBIOS1 manufacturer.",
2296 format_description
=> 'string',
2297 description
=> "Set SMBIOS1 product ID.",
2303 format_description
=> 'string',
2304 description
=> "Set SMBIOS1 SKU string.",
2310 format_description
=> 'string',
2311 description
=> "Set SMBIOS1 family string.",
2319 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2326 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2329 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2331 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2332 sub verify_bootdisk
{
2333 my ($value, $noerr) = @_;
2335 return $value if is_valid_drivename
($value);
2337 return undef if $noerr;
2339 die "invalid boot disk '$value'\n";
2342 sub parse_watchdog
{
2345 return undef if !$value;
2347 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2352 sub parse_guest_agent
{
2355 return {} if !defined($value->{agent
});
2357 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2360 # if the agent is disabled ignore the other potentially set properties
2361 return {} if !$res->{enabled
};
2368 return {} if !$value;
2369 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2374 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2375 sub verify_usb_device
{
2376 my ($value, $noerr) = @_;
2378 return $value if parse_usb_device
($value);
2380 return undef if $noerr;
2382 die "unable to parse usb device\n";
2385 # add JSON properties for create and set function
2386 sub json_config_properties
{
2389 foreach my $opt (keys %$confdesc) {
2390 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2391 $prop->{$opt} = $confdesc->{$opt};
2397 # return copy of $confdesc_cloudinit to generate documentation
2398 sub cloudinit_config_properties
{
2400 return dclone
($confdesc_cloudinit);
2404 my ($key, $value) = @_;
2406 die "unknown setting '$key'\n" if !$confdesc->{$key};
2408 my $type = $confdesc->{$key}->{type
};
2410 if (!defined($value)) {
2411 die "got undefined value\n";
2414 if ($value =~ m/[\n\r]/) {
2415 die "property contains a line feed\n";
2418 if ($type eq 'boolean') {
2419 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2420 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2421 die "type check ('boolean') failed - got '$value'\n";
2422 } elsif ($type eq 'integer') {
2423 return int($1) if $value =~ m/^(\d+)$/;
2424 die "type check ('integer') failed - got '$value'\n";
2425 } elsif ($type eq 'number') {
2426 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2427 die "type check ('number') failed - got '$value'\n";
2428 } elsif ($type eq 'string') {
2429 if (my $fmt = $confdesc->{$key}->{format
}) {
2430 PVE
::JSONSchema
::check_format
($fmt, $value);
2433 $value =~ s/^\"(.*)\"$/$1/;
2436 die "internal error"
2440 sub check_iommu_support
{
2441 #fixme : need to check IOMMU support
2442 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2452 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2453 utime undef, undef, $conf;
2457 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2459 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2461 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2463 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2465 if ($conf->{template
}) {
2466 # check if any base image is still used by a linked clone
2467 foreach_drive
($conf, sub {
2468 my ($ds, $drive) = @_;
2470 return if drive_is_cdrom
($drive);
2472 my $volid = $drive->{file
};
2474 return if !$volid || $volid =~ m
|^/|;
2476 die "base volume '$volid' is still in use by linked cloned\n"
2477 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2482 # only remove disks owned by this VM
2483 foreach_drive
($conf, sub {
2484 my ($ds, $drive) = @_;
2486 return if drive_is_cdrom
($drive, 1);
2488 my $volid = $drive->{file
};
2490 return if !$volid || $volid =~ m
|^/|;
2492 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2493 return if !$path || !$owner || ($owner != $vmid);
2496 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2498 warn "Could not remove disk '$volid', check manually: $@" if $@;
2502 if ($keep_empty_config) {
2503 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2508 # also remove unused disk
2510 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2513 PVE
::Storage
::foreach_volid
($dl, sub {
2514 my ($volid, $sid, $volname, $d) = @_;
2515 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2524 sub parse_vm_config
{
2525 my ($filename, $raw) = @_;
2527 return undef if !defined($raw);
2530 digest
=> Digest
::SHA
::sha1_hex
($raw),
2535 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2536 || die "got strange filename '$filename'";
2544 my @lines = split(/\n/, $raw);
2545 foreach my $line (@lines) {
2546 next if $line =~ m/^\s*$/;
2548 if ($line =~ m/^\[PENDING\]\s*$/i) {
2549 $section = 'pending';
2550 if (defined($descr)) {
2552 $conf->{description
} = $descr;
2555 $conf = $res->{$section} = {};
2558 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2560 if (defined($descr)) {
2562 $conf->{description
} = $descr;
2565 $conf = $res->{snapshots
}->{$section} = {};
2569 if ($line =~ m/^\#(.*)\s*$/) {
2570 $descr = '' if !defined($descr);
2571 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2575 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2576 $descr = '' if !defined($descr);
2577 $descr .= PVE
::Tools
::decode_text
($2);
2578 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2579 $conf->{snapstate
} = $1;
2580 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2583 $conf->{$key} = $value;
2584 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2586 if ($section eq 'pending') {
2587 $conf->{delete} = $value; # we parse this later
2589 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2591 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2594 eval { $value = check_type
($key, $value); };
2596 warn "vm $vmid - unable to parse value of '$key' - $@";
2598 $key = 'ide2' if $key eq 'cdrom';
2599 my $fmt = $confdesc->{$key}->{format
};
2600 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2601 my $v = parse_drive
($key, $value);
2602 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2603 $v->{file
} = $volid;
2604 $value = print_drive
($vmid, $v);
2606 warn "vm $vmid - unable to parse value of '$key'\n";
2611 $conf->{$key} = $value;
2616 if (defined($descr)) {
2618 $conf->{description
} = $descr;
2620 delete $res->{snapstate
}; # just to be sure
2625 sub write_vm_config
{
2626 my ($filename, $conf) = @_;
2628 delete $conf->{snapstate
}; # just to be sure
2630 if ($conf->{cdrom
}) {
2631 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2632 $conf->{ide2
} = $conf->{cdrom
};
2633 delete $conf->{cdrom
};
2636 # we do not use 'smp' any longer
2637 if ($conf->{sockets
}) {
2638 delete $conf->{smp
};
2639 } elsif ($conf->{smp
}) {
2640 $conf->{sockets
} = $conf->{smp
};
2641 delete $conf->{cores
};
2642 delete $conf->{smp
};
2645 my $used_volids = {};
2647 my $cleanup_config = sub {
2648 my ($cref, $pending, $snapname) = @_;
2650 foreach my $key (keys %$cref) {
2651 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2652 $key eq 'snapstate' || $key eq 'pending';
2653 my $value = $cref->{$key};
2654 if ($key eq 'delete') {
2655 die "propertry 'delete' is only allowed in [PENDING]\n"
2657 # fixme: check syntax?
2660 eval { $value = check_type
($key, $value); };
2661 die "unable to parse value of '$key' - $@" if $@;
2663 $cref->{$key} = $value;
2665 if (!$snapname && is_valid_drivename
($key)) {
2666 my $drive = parse_drive
($key, $value);
2667 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2672 &$cleanup_config($conf);
2674 &$cleanup_config($conf->{pending
}, 1);
2676 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2677 die "internal error" if $snapname eq 'pending';
2678 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2681 # remove 'unusedX' settings if we re-add a volume
2682 foreach my $key (keys %$conf) {
2683 my $value = $conf->{$key};
2684 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2685 delete $conf->{$key};
2689 my $generate_raw_config = sub {
2690 my ($conf, $pending) = @_;
2694 # add description as comment to top of file
2695 if (defined(my $descr = $conf->{description
})) {
2697 foreach my $cl (split(/\n/, $descr)) {
2698 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2701 $raw .= "#\n" if $pending;
2705 foreach my $key (sort keys %$conf) {
2706 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2707 $raw .= "$key: $conf->{$key}\n";
2712 my $raw = &$generate_raw_config($conf);
2714 if (scalar(keys %{$conf->{pending
}})){
2715 $raw .= "\n[PENDING]\n";
2716 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2719 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2720 $raw .= "\n[$snapname]\n";
2721 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2731 # we use static defaults from our JSON schema configuration
2732 foreach my $key (keys %$confdesc) {
2733 if (defined(my $default = $confdesc->{$key}->{default})) {
2734 $res->{$key} = $default;
2742 my $vmlist = PVE
::Cluster
::get_vmlist
();
2744 return $res if !$vmlist || !$vmlist->{ids
};
2745 my $ids = $vmlist->{ids
};
2747 foreach my $vmid (keys %$ids) {
2748 my $d = $ids->{$vmid};
2749 next if !$d->{node
} || $d->{node
} ne $nodename;
2750 next if !$d->{type
} || $d->{type
} ne 'qemu';
2751 $res->{$vmid}->{exists} = 1;
2756 # test if VM uses local resources (to prevent migration)
2757 sub check_local_resources
{
2758 my ($conf, $noerr) = @_;
2762 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2763 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2765 foreach my $k (keys %$conf) {
2766 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2767 # sockets are safe: they will recreated be on the target side post-migrate
2768 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2769 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2772 die "VM uses local resources\n" if $loc_res && !$noerr;
2777 # check if used storages are available on all nodes (use by migrate)
2778 sub check_storage_availability
{
2779 my ($storecfg, $conf, $node) = @_;
2781 foreach_drive
($conf, sub {
2782 my ($ds, $drive) = @_;
2784 my $volid = $drive->{file
};
2787 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2790 # check if storage is available on both nodes
2791 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2792 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2796 # list nodes where all VM images are available (used by has_feature API)
2798 my ($conf, $storecfg) = @_;
2800 my $nodelist = PVE
::Cluster
::get_nodelist
();
2801 my $nodehash = { map { $_ => 1 } @$nodelist };
2802 my $nodename = PVE
::INotify
::nodename
();
2804 foreach_drive
($conf, sub {
2805 my ($ds, $drive) = @_;
2807 my $volid = $drive->{file
};
2810 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2812 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2813 if ($scfg->{disable
}) {
2815 } elsif (my $avail = $scfg->{nodes
}) {
2816 foreach my $node (keys %$nodehash) {
2817 delete $nodehash->{$node} if !$avail->{$node};
2819 } elsif (!$scfg->{shared
}) {
2820 foreach my $node (keys %$nodehash) {
2821 delete $nodehash->{$node} if $node ne $nodename
2831 my ($pidfile, $pid) = @_;
2833 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2837 return undef if !$line;
2838 my @param = split(/\0/, $line);
2840 my $cmd = $param[0];
2841 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2843 for (my $i = 0; $i < scalar (@param); $i++) {
2846 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2847 my $p = $param[$i+1];
2848 return 1 if $p && ($p eq $pidfile);
2857 my ($vmid, $nocheck, $node) = @_;
2859 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2861 die "unable to find configuration file for VM $vmid - no such machine\n"
2862 if !$nocheck && ! -f
$filename;
2864 my $pidfile = pidfile_name
($vmid);
2866 if (my $fd = IO
::File-
>new("<$pidfile")) {
2871 my $mtime = $st->mtime;
2872 if ($mtime > time()) {
2873 warn "file '$filename' modified in future\n";
2876 if ($line =~ m/^(\d+)$/) {
2878 if (check_cmdline
($pidfile, $pid)) {
2879 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2891 my $vzlist = config_list
();
2893 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2895 while (defined(my $de = $fd->read)) {
2896 next if $de !~ m/^(\d+)\.pid$/;
2898 next if !defined($vzlist->{$vmid});
2899 if (my $pid = check_running
($vmid)) {
2900 $vzlist->{$vmid}->{pid
} = $pid;
2908 my ($storecfg, $conf) = @_;
2910 my $bootdisk = $conf->{bootdisk
};
2911 return undef if !$bootdisk;
2912 return undef if !is_valid_drivename
($bootdisk);
2914 return undef if !$conf->{$bootdisk};
2916 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2917 return undef if !defined($drive);
2919 return undef if drive_is_cdrom
($drive);
2921 my $volid = $drive->{file
};
2922 return undef if !$volid;
2924 return $drive->{size
};
2927 our $vmstatus_return_properties = {
2928 vmid
=> get_standard_option
('pve-vmid'),
2930 description
=> "Qemu process status.",
2932 enum
=> ['stopped', 'running'],
2935 description
=> "Maximum memory in bytes.",
2938 renderer
=> 'bytes',
2941 description
=> "Root disk size in bytes.",
2944 renderer
=> 'bytes',
2947 description
=> "VM name.",
2952 description
=> "Qemu QMP agent status.",
2957 description
=> "PID of running qemu process.",
2962 description
=> "Uptime.",
2965 renderer
=> 'duration',
2968 description
=> "Maximum usable CPUs.",
2974 my $last_proc_pid_stat;
2976 # get VM status information
2977 # This must be fast and should not block ($full == false)
2978 # We only query KVM using QMP if $full == true (this can be slow)
2980 my ($opt_vmid, $full) = @_;
2984 my $storecfg = PVE
::Storage
::config
();
2986 my $list = vzlist
();
2987 my $defaults = load_defaults
();
2989 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2991 my $cpucount = $cpuinfo->{cpus
} || 1;
2993 foreach my $vmid (keys %$list) {
2994 next if $opt_vmid && ($vmid ne $opt_vmid);
2996 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2997 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2999 my $d = { vmid
=> $vmid };
3000 $d->{pid
} = $list->{$vmid}->{pid
};
3002 # fixme: better status?
3003 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3005 my $size = disksize
($storecfg, $conf);
3006 if (defined($size)) {
3007 $d->{disk
} = 0; # no info available
3008 $d->{maxdisk
} = $size;
3014 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3015 * ($conf->{cores
} || $defaults->{cores
});
3016 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3017 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3019 $d->{name
} = $conf->{name
} || "VM $vmid";
3020 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3021 : $defaults->{memory
}*(1024*1024);
3023 if ($conf->{balloon
}) {
3024 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3025 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3026 : $defaults->{shares
};
3037 $d->{diskwrite
} = 0;
3039 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3041 $d->{serial
} = 1 if conf_has_serial
($conf);
3046 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3047 foreach my $dev (keys %$netdev) {
3048 next if $dev !~ m/^tap([1-9]\d*)i/;
3050 my $d = $res->{$vmid};
3053 $d->{netout
} += $netdev->{$dev}->{receive
};
3054 $d->{netin
} += $netdev->{$dev}->{transmit
};
3057 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3058 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3063 my $ctime = gettimeofday
;
3065 foreach my $vmid (keys %$list) {
3067 my $d = $res->{$vmid};
3068 my $pid = $d->{pid
};
3071 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3072 next if !$pstat; # not running
3074 my $used = $pstat->{utime} + $pstat->{stime
};
3076 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3078 if ($pstat->{vsize
}) {
3079 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3082 my $old = $last_proc_pid_stat->{$pid};
3084 $last_proc_pid_stat->{$pid} = {
3092 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3094 if ($dtime > 1000) {
3095 my $dutime = $used - $old->{used
};
3097 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3098 $last_proc_pid_stat->{$pid} = {
3104 $d->{cpu
} = $old->{cpu
};
3108 return $res if !$full;
3110 my $qmpclient = PVE
::QMPClient-
>new();
3112 my $ballooncb = sub {
3113 my ($vmid, $resp) = @_;
3115 my $info = $resp->{'return'};
3116 return if !$info->{max_mem
};
3118 my $d = $res->{$vmid};
3120 # use memory assigned to VM
3121 $d->{maxmem
} = $info->{max_mem
};
3122 $d->{balloon
} = $info->{actual
};
3124 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3125 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3126 $d->{freemem
} = $info->{free_mem
};
3129 $d->{ballooninfo
} = $info;
3132 my $blockstatscb = sub {
3133 my ($vmid, $resp) = @_;
3134 my $data = $resp->{'return'} || [];
3135 my $totalrdbytes = 0;
3136 my $totalwrbytes = 0;
3138 for my $blockstat (@$data) {
3139 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3140 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3142 $blockstat->{device
} =~ s/drive-//;
3143 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3145 $res->{$vmid}->{diskread
} = $totalrdbytes;
3146 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3149 my $statuscb = sub {
3150 my ($vmid, $resp) = @_;
3152 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3153 # this fails if ballon driver is not loaded, so this must be
3154 # the last commnand (following command are aborted if this fails).
3155 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3157 my $status = 'unknown';
3158 if (!defined($status = $resp->{'return'}->{status
})) {
3159 warn "unable to get VM status\n";
3163 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3166 foreach my $vmid (keys %$list) {
3167 next if $opt_vmid && ($vmid ne $opt_vmid);
3168 next if !$res->{$vmid}->{pid
}; # not running
3169 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3172 $qmpclient->queue_execute(undef, 2);
3174 foreach my $vmid (keys %$list) {
3175 next if $opt_vmid && ($vmid ne $opt_vmid);
3176 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3183 my ($conf, $func, @param) = @_;
3185 foreach my $ds (valid_drive_names
()) {
3186 next if !defined($conf->{$ds});
3188 my $drive = parse_drive
($ds, $conf->{$ds});
3191 &$func($ds, $drive, @param);
3196 my ($conf, $func, @param) = @_;
3200 my $test_volid = sub {
3201 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3205 $volhash->{$volid}->{cdrom
} //= 1;
3206 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3208 $volhash->{$volid}->{replicate
} //= 0;
3209 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3211 $volhash->{$volid}->{shared
} //= 0;
3212 $volhash->{$volid}->{shared
} = 1 if $shared;
3214 $volhash->{$volid}->{referenced_in_config
} //= 0;
3215 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3217 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3218 if defined($snapname);
3221 foreach_drive
($conf, sub {
3222 my ($ds, $drive) = @_;
3223 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3226 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3227 my $snap = $conf->{snapshots
}->{$snapname};
3228 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3229 foreach_drive
($snap, sub {
3230 my ($ds, $drive) = @_;
3231 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3235 foreach my $volid (keys %$volhash) {
3236 &$func($volid, $volhash->{$volid}, @param);
3240 sub conf_has_serial
{
3243 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3244 if ($conf->{"serial$i"}) {
3252 sub vga_conf_has_spice
{
3255 my $vgaconf = parse_vga
($vga);
3256 my $vgatype = $vgaconf->{type
};
3257 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3262 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3263 sub get_host_arch
() {
3264 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3270 return get_host_arch
() eq $arch;
3273 my $default_machines = {
3278 sub get_basic_machine_info
{
3279 my ($conf, $forcemachine) = @_;
3281 my $arch = $conf->{arch
} // get_host_arch
();
3282 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3283 return ($arch, $machine);
3286 sub get_ovmf_files
($) {
3289 my $ovmf = $OVMF->{$arch}
3290 or die "no OVMF images known for architecture '$arch'\n";
3296 aarch64
=> '/usr/bin/qemu-system-aarch64',
3297 x86_64
=> '/usr/bin/qemu-system-x86_64',
3299 sub get_command_for_arch
($) {
3301 return '/usr/bin/kvm' if is_native
($arch);
3303 my $cmd = $Arch2Qemu->{$arch}
3304 or die "don't know how to emulate architecture '$arch'\n";
3308 sub get_cpu_options
{
3309 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3312 my $ostype = $conf->{ostype
};
3314 my $cpu = $kvm ?
"kvm64" : "qemu64";
3315 if ($arch eq 'aarch64') {
3316 $cpu = 'cortex-a57';
3318 if (my $cputype = $conf->{cpu
}) {
3319 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3320 or die "Cannot parse cpu description: $cputype\n";
3321 $cpu = $cpuconf->{cputype
};
3322 $kvm_off = 1 if $cpuconf->{hidden
};
3324 if (defined(my $flags = $cpuconf->{flags
})) {
3325 push @$cpuFlags, split(";", $flags);
3329 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3331 push @$cpuFlags , '-x2apic'
3332 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3334 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3336 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3338 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3340 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3341 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3344 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3346 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3348 push @$cpuFlags, 'kvm=off' if $kvm_off;
3350 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3351 push @$cpuFlags, "vendor=${cpu_vendor}"
3352 if $cpu_vendor ne 'default';
3353 } elsif ($arch ne 'aarch64') {
3354 die "internal error"; # should not happen
3357 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3359 return ('-cpu', $cpu);
3362 sub config_to_command
{
3363 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3366 my $globalFlags = [];
3367 my $machineFlags = [];
3372 my $kvmver = kvm_user_version
();
3373 my $vernum = 0; # unknown
3374 my $ostype = $conf->{ostype
};
3375 my $winversion = windows_version
($ostype);
3376 my $kvm = $conf->{kvm
};
3378 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3379 $kvm //= 1 if is_native
($arch);
3382 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3383 if !defined kvm_version
();
3386 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3387 $vernum = $1*1000000+$2*1000;
3388 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3389 $vernum = $1*1000000+$2*1000+$3;
3392 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3394 my $have_ovz = -f
'/proc/vz/vestat';
3396 my $q35 = machine_type_is_q35
($conf);
3397 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3398 my $use_old_bios_files = undef;
3399 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3401 my $cpuunits = defined($conf->{cpuunits
}) ?
3402 $conf->{cpuunits
} : $defaults->{cpuunits
};
3404 push @$cmd, get_command_for_arch
($arch);
3406 push @$cmd, '-id', $vmid;
3408 my $vmname = $conf->{name
} || "vm$vmid";
3410 push @$cmd, '-name', $vmname;
3414 my $qmpsocket = qmp_socket
($vmid);
3415 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3416 push @$cmd, '-mon', "chardev=qmp,mode=control";
3418 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3419 my $eventsocket = qmp_socket
($vmid, 0, 'event');
3420 push @$cmd, '-chardev', "socket,id=qmp-event,path=$eventsocket,server,nowait";
3421 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3424 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3426 push @$cmd, '-daemonize';
3428 if ($conf->{smbios1
}) {
3429 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3432 if ($conf->{vmgenid
}) {
3433 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3436 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3437 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3438 die "uefi base image not found\n" if ! -f
$ovmf_code;
3442 if (my $efidisk = $conf->{efidisk0
}) {
3443 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3444 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3445 $format = $d->{format
};
3447 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3448 if (!defined($format)) {
3449 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3450 $format = qemu_img_format
($scfg, $volname);
3454 die "efidisk format must be specified\n"
3455 if !defined($format);
3458 warn "no efidisk configured! Using temporary efivars disk.\n";
3459 $path = "/tmp/$vmid-ovmf.fd";
3460 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3464 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3465 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3469 # add usb controllers
3470 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3471 push @$devices, @usbcontrollers if @usbcontrollers;
3472 my $vga = parse_vga
($conf->{vga
});
3474 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3475 $vga->{type
} = 'qxl' if $qxlnum;
3477 if (!$vga->{type
}) {
3478 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3479 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3481 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3485 # enable absolute mouse coordinates (needed by vnc)
3487 if (defined($conf->{tablet
})) {
3488 $tablet = $conf->{tablet
};
3490 $tablet = $defaults->{tablet
};
3491 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3492 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3495 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3498 my $gpu_passthrough;
3501 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3502 my $d = parse_hostpci
($conf->{"hostpci$i"});
3505 my $pcie = $d->{pcie
};
3507 die "q35 machine model is not enabled" if !$q35;
3508 $pciaddr = print_pcie_addr
("hostpci$i");
3510 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3513 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3514 my $romfile = $d->{romfile
};
3517 if ($d->{'x-vga'}) {
3518 $xvga = ',x-vga=on';
3520 $vga->{type
} = 'none';
3521 $gpu_passthrough = 1;
3523 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3527 my $pcidevices = $d->{pciid
};
3528 my $multifunction = 1 if @$pcidevices > 1;
3531 foreach my $pcidevice (@$pcidevices) {
3533 my $id = "hostpci$i";
3534 $id .= ".$j" if $multifunction;
3535 my $addr = $pciaddr;
3536 $addr .= ".$j" if $multifunction;
3537 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3540 $devicestr .= "$rombar$xvga";
3541 $devicestr .= ",multifunction=on" if $multifunction;
3542 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3545 push @$devices, '-device', $devicestr;
3551 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3552 push @$devices, @usbdevices if @usbdevices;
3554 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3555 if (my $path = $conf->{"serial$i"}) {
3556 if ($path eq 'socket') {
3557 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3558 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3559 push @$devices, '-device', "isa-serial,chardev=serial$i";
3561 die "no such serial device\n" if ! -c
$path;
3562 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3563 push @$devices, '-device', "isa-serial,chardev=serial$i";
3569 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3570 if (my $path = $conf->{"parallel$i"}) {
3571 die "no such parallel device\n" if ! -c
$path;
3572 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3573 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3574 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3580 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3581 $sockets = $conf->{sockets
} if $conf->{sockets
};
3583 my $cores = $conf->{cores
} || 1;
3585 my $maxcpus = $sockets * $cores;
3587 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3589 my $allowed_vcpus = $cpuinfo->{cpus
};
3591 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3592 if ($allowed_vcpus < $maxcpus);
3594 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3596 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3597 for (my $i = 2; $i <= $vcpus; $i++) {
3598 my $cpustr = print_cpu_device
($conf,$i);
3599 push @$cmd, '-device', $cpustr;
3604 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3606 push @$cmd, '-nodefaults';
3608 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3610 my $bootindex_hash = {};
3612 foreach my $o (split(//, $bootorder)) {
3613 $bootindex_hash->{$o} = $i*100;
3617 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3619 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3621 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3623 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3624 push @$devices, '-device', print_vga_device
($conf, $vga, undef, $qxlnum, $bridges);
3625 my $socket = vnc_socket
($vmid);
3626 push @$cmd, '-vnc', "unix:$socket,x509,password";
3628 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3629 push @$cmd, '-nographic';
3633 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3635 my $useLocaltime = $conf->{localtime};
3637 if ($winversion >= 5) { # windows
3638 $useLocaltime = 1 if !defined($conf->{localtime});
3640 # use time drift fix when acpi is enabled
3641 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3642 $tdf = 1 if !defined($conf->{tdf
});
3646 if ($winversion >= 6) {
3647 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3648 push @$cmd, '-no-hpet';
3651 push @$rtcFlags, 'driftfix=slew' if $tdf;
3654 push @$machineFlags, 'accel=tcg';
3657 if ($machine_type) {
3658 push @$machineFlags, "type=${machine_type}";
3661 if ($conf->{startdate
}) {
3662 push @$rtcFlags, "base=$conf->{startdate}";
3663 } elsif ($useLocaltime) {
3664 push @$rtcFlags, 'base=localtime';
3667 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3669 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3671 push @$cmd, '-S' if $conf->{freeze
};
3673 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3676 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3677 #push @$cmd, '-soundhw', 'es1370';
3678 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3680 if (parse_guest_agent
($conf)->{enabled
}) {
3681 my $qgasocket = qmp_socket
($vmid, 1);
3682 my $pciaddr = print_pci_addr
("qga0", $bridges);
3683 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3684 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3685 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3693 for(my $i = 1; $i < $qxlnum; $i++){
3694 push @$devices, '-device', print_vga_device
($conf, $vga, $i, $qxlnum, $bridges);
3697 # assume other OS works like Linux
3698 my ($ram, $vram) = ("134217728", "67108864");
3699 if ($vga->{memory
}) {
3700 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3701 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3703 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3704 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3708 my $pciaddr = print_pci_addr
("spice", $bridges);
3710 my $nodename = PVE
::INotify
::nodename
();
3711 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3712 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3713 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3714 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3715 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3717 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3719 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3720 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3721 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3724 # enable balloon by default, unless explicitly disabled
3725 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3726 $pciaddr = print_pci_addr
("balloon0", $bridges);
3727 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3730 if ($conf->{watchdog
}) {
3731 my $wdopts = parse_watchdog
($conf->{watchdog
});
3732 $pciaddr = print_pci_addr
("watchdog", $bridges);
3733 my $watchdog = $wdopts->{model
} || 'i6300esb';
3734 push @$devices, '-device', "$watchdog$pciaddr";
3735 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3739 my $scsicontroller = {};
3740 my $ahcicontroller = {};
3741 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3743 # Add iscsi initiator name if available
3744 if (my $initiator = get_initiator_name
()) {
3745 push @$devices, '-iscsi', "initiator-name=$initiator";
3748 foreach_drive
($conf, sub {
3749 my ($ds, $drive) = @_;
3751 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3752 push @$vollist, $drive->{file
};
3755 # ignore efidisk here, already added in bios/fw handling code above
3756 return if $drive->{interface
} eq 'efidisk';
3758 $use_virtio = 1 if $ds =~ m/^virtio/;
3760 if (drive_is_cdrom
($drive)) {
3761 if ($bootindex_hash->{d
}) {
3762 $drive->{bootindex
} = $bootindex_hash->{d
};
3763 $bootindex_hash->{d
} += 1;
3766 if ($bootindex_hash->{c
}) {
3767 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3768 $bootindex_hash->{c
} += 1;
3772 if($drive->{interface
} eq 'virtio'){
3773 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3776 if ($drive->{interface
} eq 'scsi') {
3778 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3780 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3781 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3784 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3785 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3786 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3787 } elsif ($drive->{iothread
}) {
3788 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3792 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3793 $queues = ",num_queues=$drive->{queues}";
3796 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3797 $scsicontroller->{$controller}=1;
3800 if ($drive->{interface
} eq 'sata') {
3801 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3802 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3803 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3804 $ahcicontroller->{$controller}=1;
3807 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3808 push @$devices, '-drive',$drive_cmd;
3809 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3812 for (my $i = 0; $i < $MAX_NETS; $i++) {
3813 next if !$conf->{"net$i"};
3814 my $d = parse_net
($conf->{"net$i"});
3817 $use_virtio = 1 if $d->{model
} eq 'virtio';
3819 if ($bootindex_hash->{n
}) {
3820 $d->{bootindex
} = $bootindex_hash->{n
};
3821 $bootindex_hash->{n
} += 1;
3824 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3825 push @$devices, '-netdev', $netdevfull;
3827 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3828 push @$devices, '-device', $netdevicefull;
3833 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3838 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3840 while (my ($k, $v) = each %$bridges) {
3841 $pciaddr = print_pci_addr
("pci.$k");
3842 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3847 if ($conf->{args
}) {
3848 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3852 push @$cmd, @$devices;
3853 push @$cmd, '-rtc', join(',', @$rtcFlags)
3854 if scalar(@$rtcFlags);
3855 push @$cmd, '-machine', join(',', @$machineFlags)
3856 if scalar(@$machineFlags);
3857 push @$cmd, '-global', join(',', @$globalFlags)
3858 if scalar(@$globalFlags);
3860 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3865 return "${var_run_tmpdir}/$vmid.vnc";
3871 my $res = vm_mon_cmd
($vmid, 'query-spice');
3873 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3877 my ($vmid, $qga, $name) = @_;
3878 my $sockettype = $qga ?
'qga' : 'qmp';
3879 my $ext = $name ?
'-'.$name : '';
3880 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3885 return "${var_run_tmpdir}/$vmid.pid";
3888 sub vm_devices_list
{
3891 my $res = vm_mon_cmd
($vmid, 'query-pci');
3892 my $devices_to_check = [];
3894 foreach my $pcibus (@$res) {
3895 push @$devices_to_check, @{$pcibus->{devices
}},
3898 while (@$devices_to_check) {
3900 for my $d (@$devices_to_check) {
3901 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3902 next if !$d->{'pci_bridge'};
3904 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3905 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3907 $devices_to_check = $to_check;
3910 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3911 foreach my $block (@$resblock) {
3912 if($block->{device
} =~ m/^drive-(\S+)/){
3917 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3918 foreach my $mice (@$resmice) {
3919 if ($mice->{name
} eq 'QEMU HID Tablet') {
3920 $devices->{tablet
} = 1;
3925 # for usb devices there is no query-usb
3926 # but we can iterate over the entries in
3927 # qom-list path=/machine/peripheral
3928 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3929 foreach my $per (@$resperipheral) {
3930 if ($per->{name
} =~ m/^usb\d+$/) {
3931 $devices->{$per->{name
}} = 1;
3939 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3941 my $q35 = machine_type_is_q35
($conf);
3943 my $devices_list = vm_devices_list
($vmid);
3944 return 1 if defined($devices_list->{$deviceid});
3946 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3948 if ($deviceid eq 'tablet') {
3950 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3952 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3954 die "usb hotplug currently not reliable\n";
3955 # since we can't reliably hot unplug all added usb devices
3956 # and usb passthrough disables live migration
3957 # we disable usb hotplugging for now
3958 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3960 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3962 qemu_iothread_add
($vmid, $deviceid, $device);
3964 qemu_driveadd
($storecfg, $vmid, $device);
3965 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3967 qemu_deviceadd
($vmid, $devicefull);
3968 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3970 eval { qemu_drivedel
($vmid, $deviceid); };
3975 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3978 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3979 my $pciaddr = print_pci_addr
($deviceid);
3980 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3982 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3984 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3985 qemu_iothread_add
($vmid, $deviceid, $device);
3986 $devicefull .= ",iothread=iothread-$deviceid";
3989 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3990 $devicefull .= ",num_queues=$device->{queues}";
3993 qemu_deviceadd
($vmid, $devicefull);
3994 qemu_deviceaddverify
($vmid, $deviceid);
3996 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3998 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3999 qemu_driveadd
($storecfg, $vmid, $device);
4001 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
4002 eval { qemu_deviceadd
($vmid, $devicefull); };
4004 eval { qemu_drivedel
($vmid, $deviceid); };
4009 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4011 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
4013 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4014 my $use_old_bios_files = undef;
4015 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4017 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
4018 qemu_deviceadd
($vmid, $netdevicefull);
4019 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4021 eval { qemu_netdevdel
($vmid, $deviceid); };
4026 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4029 my $pciaddr = print_pci_addr
($deviceid);
4030 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4032 qemu_deviceadd
($vmid, $devicefull);
4033 qemu_deviceaddverify
($vmid, $deviceid);
4036 die "can't hotplug device '$deviceid'\n";
4042 # fixme: this should raise exceptions on error!
4043 sub vm_deviceunplug
{
4044 my ($vmid, $conf, $deviceid) = @_;
4046 my $devices_list = vm_devices_list
($vmid);
4047 return 1 if !defined($devices_list->{$deviceid});
4049 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4051 if ($deviceid eq 'tablet') {
4053 qemu_devicedel
($vmid, $deviceid);
4055 } elsif ($deviceid =~ m/^usb\d+$/) {
4057 die "usb hotplug currently not reliable\n";
4058 # when unplugging usb devices this way,
4059 # there may be remaining usb controllers/hubs
4060 # so we disable it for now
4061 qemu_devicedel
($vmid, $deviceid);
4062 qemu_devicedelverify
($vmid, $deviceid);
4064 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4066 qemu_devicedel
($vmid, $deviceid);
4067 qemu_devicedelverify
($vmid, $deviceid);
4068 qemu_drivedel
($vmid, $deviceid);
4069 qemu_iothread_del
($conf, $vmid, $deviceid);
4071 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4073 qemu_devicedel
($vmid, $deviceid);
4074 qemu_devicedelverify
($vmid, $deviceid);
4075 qemu_iothread_del
($conf, $vmid, $deviceid);
4077 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4079 qemu_devicedel
($vmid, $deviceid);
4080 qemu_drivedel
($vmid, $deviceid);
4081 qemu_deletescsihw
($conf, $vmid, $deviceid);
4083 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4085 qemu_devicedel
($vmid, $deviceid);
4086 qemu_devicedelverify
($vmid, $deviceid);
4087 qemu_netdevdel
($vmid, $deviceid);
4090 die "can't unplug device '$deviceid'\n";
4096 sub qemu_deviceadd
{
4097 my ($vmid, $devicefull) = @_;
4099 $devicefull = "driver=".$devicefull;
4100 my %options = split(/[=,]/, $devicefull);
4102 vm_mon_cmd
($vmid, "device_add" , %options);
4105 sub qemu_devicedel
{
4106 my ($vmid, $deviceid) = @_;
4108 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4111 sub qemu_iothread_add
{
4112 my($vmid, $deviceid, $device) = @_;
4114 if ($device->{iothread
}) {
4115 my $iothreads = vm_iothreads_list
($vmid);
4116 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4120 sub qemu_iothread_del
{
4121 my($conf, $vmid, $deviceid) = @_;
4123 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4124 if ($device->{iothread
}) {
4125 my $iothreads = vm_iothreads_list
($vmid);
4126 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4130 sub qemu_objectadd
{
4131 my($vmid, $objectid, $qomtype) = @_;
4133 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4138 sub qemu_objectdel
{
4139 my($vmid, $objectid) = @_;
4141 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4147 my ($storecfg, $vmid, $device) = @_;
4149 my $drive = print_drive_full
($storecfg, $vmid, $device);
4150 $drive =~ s/\\/\\\\/g;
4151 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4153 # If the command succeeds qemu prints: "OK
"
4154 return 1 if $ret =~ m/OK/s;
4156 die "adding drive failed
: $ret\n";
4160 my($vmid, $deviceid) = @_;
4162 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4165 return 1 if $ret eq "";
4167 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4168 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4170 die "deleting drive
$deviceid failed
: $ret\n";
4173 sub qemu_deviceaddverify {
4174 my ($vmid, $deviceid) = @_;
4176 for (my $i = 0; $i <= 5; $i++) {
4177 my $devices_list = vm_devices_list($vmid);
4178 return 1 if defined($devices_list->{$deviceid});
4182 die "error on hotplug device
'$deviceid'\n";
4186 sub qemu_devicedelverify {
4187 my ($vmid, $deviceid) = @_;
4189 # need to verify that the device is correctly removed as device_del
4190 # is async and empty return is not reliable
4192 for (my $i = 0; $i <= 5; $i++) {
4193 my $devices_list = vm_devices_list($vmid);
4194 return 1 if !defined($devices_list->{$deviceid});
4198 die "error on hot-unplugging device
'$deviceid'\n";
4201 sub qemu_findorcreatescsihw {
4202 my ($storecfg, $conf, $vmid, $device) = @_;
4204 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4206 my $scsihwid="$controller_prefix$controller";
4207 my $devices_list = vm_devices_list($vmid);
4209 if(!defined($devices_list->{$scsihwid})) {
4210 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
4216 sub qemu_deletescsihw {
4217 my ($conf, $vmid, $opt) = @_;
4219 my $device = parse_drive($opt, $conf->{$opt});
4221 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4222 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4226 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4228 my $devices_list = vm_devices_list($vmid);
4229 foreach my $opt (keys %{$devices_list}) {
4230 if (PVE::QemuServer::is_valid_drivename($opt)) {
4231 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4232 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4238 my $scsihwid="scsihw
$controller";
4240 vm_deviceunplug($vmid, $conf, $scsihwid);
4245 sub qemu_add_pci_bridge {
4246 my ($storecfg, $conf, $vmid, $device) = @_;
4252 print_pci_addr($device, $bridges);
4254 while (my ($k, $v) = each %$bridges) {
4257 return 1 if !defined($bridgeid) || $bridgeid < 1;
4259 my $bridge = "pci
.$bridgeid";
4260 my $devices_list = vm_devices_list($vmid);
4262 if (!defined($devices_list->{$bridge})) {
4263 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
4269 sub qemu_set_link_status {
4270 my ($vmid, $device, $up) = @_;
4272 vm_mon_cmd($vmid, "set_link
", name => $device,
4273 up => $up ? JSON::true : JSON::false);
4276 sub qemu_netdevadd {
4277 my ($vmid, $conf, $device, $deviceid) = @_;
4279 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
4280 my %options = split(/[=,]/, $netdev);
4282 vm_mon_cmd($vmid, "netdev_add
", %options);
4286 sub qemu_netdevdel {
4287 my ($vmid, $deviceid) = @_;
4289 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4292 sub qemu_usb_hotplug {
4293 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4297 # remove the old one first
4298 vm_deviceunplug($vmid, $conf, $deviceid);
4300 # check if xhci controller is necessary and available
4301 if ($device->{usb3}) {
4303 my $devicelist = vm_devices_list($vmid);
4305 if (!$devicelist->{xhci}) {
4306 my $pciaddr = print_pci_addr("xhci
");
4307 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4310 my $d = parse_usb_device($device->{host});
4311 $d->{usb3} = $device->{usb3};
4314 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4317 sub qemu_cpu_hotplug {
4318 my ($vmid, $conf, $vcpus) = @_;
4320 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4323 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4324 $sockets = $conf->{sockets} if $conf->{sockets};
4325 my $cores = $conf->{cores} || 1;
4326 my $maxcpus = $sockets * $cores;
4328 $vcpus = $maxcpus if !$vcpus;
4330 die "you can
't add more vcpus than maxcpus\n"
4331 if $vcpus > $maxcpus;
4333 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4335 if ($vcpus < $currentvcpus) {
4337 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4339 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4340 qemu_devicedel($vmid, "cpu$i");
4342 my $currentrunningvcpus = undef;
4344 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4345 last if scalar(@{$currentrunningvcpus}) == $i-1;
4346 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4350 #update conf after each succesfull cpu unplug
4351 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4352 PVE::QemuConfig->write_config($vmid, $conf);
4355 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4361 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4362 die "vcpus in running vm does not match its configuration\n"
4363 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4365 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4367 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4368 my $cpustr = print_cpu_device($conf, $i);
4369 qemu_deviceadd($vmid, $cpustr);
4372 my $currentrunningvcpus = undef;
4374 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4375 last if scalar(@{$currentrunningvcpus}) == $i;
4376 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4380 #update conf after each succesfull cpu hotplug
4381 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4382 PVE::QemuConfig->write_config($vmid, $conf);
4386 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4387 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4392 sub qemu_block_set_io_throttle {
4393 my ($vmid, $deviceid,
4394 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4395 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4396 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4397 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4399 return if !check_running($vmid) ;
4401 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4403 bps_rd => int($bps_rd),
4404 bps_wr => int($bps_wr),
4406 iops_rd => int($iops_rd),
4407 iops_wr => int($iops_wr),
4408 bps_max => int($bps_max),
4409 bps_rd_max => int($bps_rd_max),
4410 bps_wr_max => int($bps_wr_max),
4411 iops_max => int($iops_max),
4412 iops_rd_max => int($iops_rd_max),
4413 iops_wr_max => int($iops_wr_max),
4414 bps_max_length => int($bps_max_length),
4415 bps_rd_max_length => int($bps_rd_max_length),
4416 bps_wr_max_length => int($bps_wr_max_length),
4417 iops_max_length => int($iops_max_length),
4418 iops_rd_max_length => int($iops_rd_max_length),
4419 iops_wr_max_length => int($iops_wr_max_length),
4424 # old code, only used to shutdown old VM after update
4426 my ($fh, $timeout) = @_;
4428 my $sel = new IO::Select;
4435 while (scalar (@ready = $sel->can_read($timeout))) {
4437 if ($count = $fh->sysread($buf, 8192)) {
4438 if ($buf =~ /^(.*)\(qemu\) $/s) {
4445 if (!defined($count)) {
4452 die "monitor read timeout\n" if !scalar(@ready);
4457 sub qemu_block_resize {
4458 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4460 my $running = check_running($vmid);
4462 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4464 return if !$running;
4466 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4470 sub qemu_volume_snapshot {
4471 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4473 my $running = check_running($vmid);
4475 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4476 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4478 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4482 sub qemu_volume_snapshot_delete {
4483 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4485 my $running = check_running($vmid);
4490 my $conf = PVE::QemuConfig->load_config($vmid);
4491 foreach_drive($conf, sub {
4492 my ($ds, $drive) = @_;
4493 $running = 1 if $drive->{file} eq $volid;
4497 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4498 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4500 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4504 sub set_migration_caps {
4510 "auto-converge" => 1,
4512 "x-rdma-pin-all" => 0,
4517 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4519 for my $supported_capability (@$supported_capabilities) {
4521 capability => $supported_capability->{capability},
4522 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4526 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4529 my $fast_plug_option = {
4537 'vmstatestorage
' => 1,
4540 # hotplug changes in [PENDING]
4541 # $selection hash can be used to only apply specified options, for
4542 # example: { cores => 1 } (only apply changed 'cores
')
4543 # $errors ref is used to return error messages
4544 sub vmconfig_hotplug_pending {
4545 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4547 my $defaults = load_defaults();
4549 # commit values which do not have any impact on running VM first
4550 # Note: those option cannot raise errors, we we do not care about
4551 # $selection and always apply them.
4553 my $add_error = sub {
4554 my ($opt, $msg) = @_;
4555 $errors->{$opt} = "hotplug problem - $msg";
4559 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4560 if ($fast_plug_option->{$opt}) {
4561 $conf->{$opt} = $conf->{pending}->{$opt};
4562 delete $conf->{pending}->{$opt};
4568 PVE::QemuConfig->write_config($vmid, $conf);
4569 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4572 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4574 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4575 while (my ($opt, $force) = each %$pending_delete_hash) {
4576 next if $selection && !$selection->{$opt};
4578 if ($opt eq 'hotplug
') {
4579 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4580 } elsif ($opt eq 'tablet
') {
4581 die "skip\n" if !$hotplug_features->{usb};
4582 if ($defaults->{tablet}) {
4583 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4585 vm_deviceunplug($vmid, $conf, $opt);
4587 } elsif ($opt =~ m/^usb\d+/) {
4589 # since we cannot reliably hot unplug usb devices
4590 # we are disabling it
4591 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4592 vm_deviceunplug($vmid, $conf, $opt);
4593 } elsif ($opt eq 'vcpus
') {
4594 die "skip\n" if !$hotplug_features->{cpu};
4595 qemu_cpu_hotplug($vmid, $conf, undef);
4596 } elsif ($opt eq 'balloon
') {
4597 # enable balloon device is not hotpluggable
4598 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4599 # here we reset the ballooning value to memory
4600 my $balloon = $conf->{memory} || $defaults->{memory};
4601 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4602 } elsif ($fast_plug_option->{$opt}) {
4604 } elsif ($opt =~ m/^net(\d+)$/) {
4605 die "skip\n" if !$hotplug_features->{network};
4606 vm_deviceunplug($vmid, $conf, $opt);
4607 } elsif (is_valid_drivename($opt)) {
4608 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4609 vm_deviceunplug($vmid, $conf, $opt);
4610 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4611 } elsif ($opt =~ m/^memory$/) {
4612 die "skip\n" if !$hotplug_features->{memory};
4613 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4614 } elsif ($opt eq 'cpuunits
') {
4615 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4616 } elsif ($opt eq 'cpulimit
') {
4617 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4623 &$add_error($opt, $err) if $err ne "skip\n";
4625 # save new config if hotplug was successful
4626 delete $conf->{$opt};
4627 vmconfig_undelete_pending_option($conf, $opt);
4628 PVE::QemuConfig->write_config($vmid, $conf);
4629 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4633 my $apply_pending_cloudinit;
4634 $apply_pending_cloudinit = sub {
4635 my ($key, $value) = @_;
4636 $apply_pending_cloudinit = sub {}; # once is enough
4638 my @cloudinit_opts = keys %$confdesc_cloudinit;
4639 foreach my $opt (keys %{$conf->{pending}}) {
4640 next if !grep { $_ eq $opt } @cloudinit_opts;
4641 $conf->{$opt} = delete $conf->{pending}->{$opt};
4644 my $new_conf = { %$conf };
4645 $new_conf->{$key} = $value;
4646 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4649 foreach my $opt (keys %{$conf->{pending}}) {
4650 next if $selection && !$selection->{$opt};
4651 my $value = $conf->{pending}->{$opt};
4653 if ($opt eq 'hotplug
') {
4654 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4655 } elsif ($opt eq 'tablet
') {
4656 die "skip\n" if !$hotplug_features->{usb};
4658 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4659 } elsif ($value == 0) {
4660 vm_deviceunplug($vmid, $conf, $opt);
4662 } elsif ($opt =~ m/^usb\d+$/) {
4664 # since we cannot reliably hot unplug usb devices
4665 # we are disabling it
4666 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4667 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4668 die "skip\n" if !$d;
4669 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4670 } elsif ($opt eq 'vcpus
') {
4671 die "skip\n" if !$hotplug_features->{cpu};
4672 qemu_cpu_hotplug($vmid, $conf, $value);
4673 } elsif ($opt eq 'balloon
') {
4674 # enable/disable balloning device is not hotpluggable
4675 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4676 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4677 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4679 # allow manual ballooning if shares is set to zero
4680 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4681 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4682 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4684 } elsif ($opt =~ m/^net(\d+)$/) {
4685 # some changes can be done without hotplug
4686 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4687 $vmid, $opt, $value);
4688 } elsif (is_valid_drivename($opt)) {
4689 # some changes can be done without hotplug
4690 my $drive = parse_drive($opt, $value);
4691 if (drive_is_cloudinit($drive)) {
4692 &$apply_pending_cloudinit($opt, $value);
4694 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4695 $vmid, $opt, $value, 1);
4696 } elsif ($opt =~ m/^memory$/) { #dimms
4697 die "skip\n" if !$hotplug_features->{memory};
4698 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4699 } elsif ($opt eq 'cpuunits
') {
4700 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4701 } elsif ($opt eq 'cpulimit
') {
4702 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4703 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4705 die "skip\n"; # skip non-hot-pluggable options
4709 &$add_error($opt, $err) if $err ne "skip\n";
4711 # save new config if hotplug was successful
4712 $conf->{$opt} = $value;
4713 delete $conf->{pending}->{$opt};
4714 PVE::QemuConfig->write_config($vmid, $conf);
4715 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4720 sub try_deallocate_drive {
4721 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4723 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4724 my $volid = $drive->{file};
4725 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4726 my $sid = PVE::Storage::parse_volume_id($volid);
4727 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4729 # check if the disk is really unused
4730 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4731 if is_volume_in_use($storecfg, $conf, $key, $volid);
4732 PVE::Storage::vdisk_free($storecfg, $volid);
4735 # If vm is not owner of this disk remove from config
4743 sub vmconfig_delete_or_detach_drive {
4744 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4746 my $drive = parse_drive($opt, $conf->{$opt});
4748 my $rpcenv = PVE::RPCEnvironment::get();
4749 my $authuser = $rpcenv->get_user();
4752 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4753 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4755 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4759 sub vmconfig_apply_pending {
4760 my ($vmid, $conf, $storecfg) = @_;
4764 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4765 while (my ($opt, $force) = each %$pending_delete_hash) {
4766 die "internal error" if $opt =~ m/^unused/;
4767 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4768 if (!defined($conf->{$opt})) {
4769 vmconfig_undelete_pending_option($conf, $opt);
4770 PVE::QemuConfig->write_config($vmid, $conf);
4771 } elsif (is_valid_drivename($opt)) {
4772 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4773 vmconfig_undelete_pending_option($conf, $opt);
4774 delete $conf->{$opt};
4775 PVE::QemuConfig->write_config($vmid, $conf);
4777 vmconfig_undelete_pending_option($conf, $opt);
4778 delete $conf->{$opt};
4779 PVE::QemuConfig->write_config($vmid, $conf);
4783 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4785 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4786 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4788 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4789 # skip if nothing changed
4790 } elsif (is_valid_drivename($opt)) {
4791 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4792 if defined($conf->{$opt});
4793 $conf->{$opt} = $conf->{pending}->{$opt};
4795 $conf->{$opt} = $conf->{pending}->{$opt};
4798 delete $conf->{pending}->{$opt};
4799 PVE::QemuConfig->write_config($vmid, $conf);
4803 my $safe_num_ne = sub {
4806 return 0 if !defined($a) && !defined($b);
4807 return 1 if !defined($a);
4808 return 1 if !defined($b);
4813 my $safe_string_ne = sub {
4816 return 0 if !defined($a) && !defined($b);
4817 return 1 if !defined($a);
4818 return 1 if !defined($b);
4823 sub vmconfig_update_net {
4824 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4826 my $newnet = parse_net($value);
4828 if ($conf->{$opt}) {
4829 my $oldnet = parse_net($conf->{$opt});
4831 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4832 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4833 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4834 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4836 # for non online change, we try to hot-unplug
4837 die "skip\n" if !$hotplug;
4838 vm_deviceunplug($vmid, $conf, $opt);
4841 die "internal error" if $opt !~ m/net(\d+)/;
4842 my $iface = "tap${vmid}i$1";
4844 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4845 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4846 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4847 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4848 PVE::Network::tap_unplug($iface);
4849 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4850 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4851 # Rate can be applied on its own but any change above needs to
4852 # include the rate in tap_plug since OVS resets everything.
4853 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4856 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4857 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4865 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4871 sub vmconfig_update_disk {
4872 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4874 # fixme: do we need force?
4876 my $drive = parse_drive($opt, $value);
4878 if ($conf->{$opt}) {
4880 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4882 my $media = $drive->{media} || 'disk
';
4883 my $oldmedia = $old_drive->{media} || 'disk
';
4884 die "unable to change media type\n" if $media ne $oldmedia;
4886 if (!drive_is_cdrom($old_drive)) {
4888 if ($drive->{file} ne $old_drive->{file}) {
4890 die "skip\n" if !$hotplug;
4892 # unplug and register as unused
4893 vm_deviceunplug($vmid, $conf, $opt);
4894 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4897 # update existing disk
4899 # skip non hotpluggable value
4900 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4901 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4902 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4903 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4908 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4909 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4910 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4911 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4912 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4913 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4914 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4915 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4916 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4917 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4918 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4919 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4920 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4921 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4922 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4923 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4924 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4925 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4927 qemu_block_set_io_throttle($vmid,"drive-$opt",
4928 ($drive->{mbps} || 0)*1024*1024,
4929 ($drive->{mbps_rd} || 0)*1024*1024,
4930 ($drive->{mbps_wr} || 0)*1024*1024,
4931 $drive->{iops} || 0,
4932 $drive->{iops_rd} || 0,
4933 $drive->{iops_wr} || 0,
4934 ($drive->{mbps_max} || 0)*1024*1024,
4935 ($drive->{mbps_rd_max} || 0)*1024*1024,
4936 ($drive->{mbps_wr_max} || 0)*1024*1024,
4937 $drive->{iops_max} || 0,
4938 $drive->{iops_rd_max} || 0,
4939 $drive->{iops_wr_max} || 0,
4940 $drive->{bps_max_length} || 1,
4941 $drive->{bps_rd_max_length} || 1,
4942 $drive->{bps_wr_max_length} || 1,
4943 $drive->{iops_max_length} || 1,
4944 $drive->{iops_rd_max_length} || 1,
4945 $drive->{iops_wr_max_length} || 1);
4954 if ($drive->{file} eq 'none
') {
4955 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4956 if (drive_is_cloudinit($old_drive)) {
4957 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4960 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4961 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4962 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4970 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4972 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4973 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4977 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4978 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4980 PVE::QemuConfig->lock_config($vmid, sub {
4981 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4983 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4985 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4987 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4989 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4990 vmconfig_apply_pending($vmid, $conf, $storecfg);
4991 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4994 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4996 my $defaults = load_defaults();
4998 # set environment variable useful inside network script
4999 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5001 my $local_volumes = {};
5003 if ($targetstorage) {
5004 foreach_drive($conf, sub {
5005 my ($ds, $drive) = @_;
5007 return if drive_is_cdrom($drive);
5009 my $volid = $drive->{file};
5013 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5015 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5016 return if $scfg->{shared};
5017 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5022 foreach my $opt (sort keys %$local_volumes) {
5024 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5025 my $drive = parse_drive($opt, $conf->{$opt});
5027 #if remote storage is specified, use default format
5028 if ($targetstorage && $targetstorage ne "1") {
5029 $storeid = $targetstorage;
5030 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5031 $format = $defFormat;
5033 #else we use same format than original
5034 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5035 $format = qemu_img_format($scfg, $volid);
5038 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5039 my $newdrive = $drive;
5040 $newdrive->{format} = $format;
5041 $newdrive->{file} = $newvolid;
5042 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5043 $local_volumes->{$opt} = $drivestr;
5044 #pass drive to conf for command line
5045 $conf->{$opt} = $drivestr;
5049 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5051 my $migrate_port = 0;
5054 if ($statefile eq 'tcp
') {
5055 my $localip = "localhost";
5056 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5057 my $nodename = PVE::INotify::nodename();
5059 if (!defined($migration_type)) {
5060 if (defined($datacenterconf->{migration}->{type})) {
5061 $migration_type = $datacenterconf->{migration}->{type};
5063 $migration_type = 'secure
';
5067 if ($migration_type eq 'insecure
') {
5068 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5069 if ($migrate_network_addr) {
5070 $localip = $migrate_network_addr;
5072 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5075 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5078 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5079 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5080 $migrate_uri = "tcp:${localip}:${migrate_port}";
5081 push @$cmd, '-incoming
', $migrate_uri;
5084 } elsif ($statefile eq 'unix
') {
5085 # should be default for secure migrations as a ssh TCP forward
5086 # tunnel is not deterministic reliable ready and fails regurarly
5087 # to set up in time, so use UNIX socket forwards
5088 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5089 unlink $socket_addr;
5091 $migrate_uri = "unix:$socket_addr";
5093 push @$cmd, '-incoming
', $migrate_uri;
5097 push @$cmd, '-loadstate
', $statefile;
5104 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5105 my $d = parse_hostpci($conf->{"hostpci$i"});
5107 my $pcidevices = $d->{pciid};
5108 foreach my $pcidevice (@$pcidevices) {
5109 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
5111 my $info = pci_device_info("0000:$pciid");
5112 die "IOMMU not present\n" if !check_iommu_support();
5113 die "no pci device info for device '$pciid'\n" if !$info;
5114 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
5115 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
5119 PVE::Storage::activate_volumes($storecfg, $vollist);
5121 if (!check_running($vmid, 1)) {
5123 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5124 outfunc => sub {}, errfunc => sub {});
5128 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5129 : $defaults->{cpuunits};
5131 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5132 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5135 Slice => 'qemu
.slice
',
5137 CPUShares => $cpuunits
5140 if (my $cpulimit = $conf->{cpulimit}) {
5141 $properties{CPUQuota} = int($cpulimit * 100);
5143 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5145 my $run_qemu = sub {
5146 PVE::Tools::run_fork sub {
5147 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5148 run_command($cmd, %run_params);
5152 if ($conf->{hugepages}) {
5155 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5156 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5158 PVE::QemuServer::Memory::hugepages_mount();
5159 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5161 eval { $run_qemu->() };
5163 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5167 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5169 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5172 eval { $run_qemu->() };
5176 # deactivate volumes if start fails
5177 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5178 die "start failed: $err";
5181 print "migration listens on $migrate_uri\n" if $migrate_uri;
5183 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5184 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5188 #start nbd server for storage migration
5189 if ($targetstorage) {
5190 my $nodename = PVE::INotify::nodename();
5191 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5192 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5193 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5194 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5196 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5198 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5200 foreach my $opt (sort keys %$local_volumes) {
5201 my $volid = $local_volumes->{$opt};
5202 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5203 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5204 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5208 if ($migratedfrom) {
5210 set_migration_caps($vmid);
5215 print "spice listens on port $spice_port\n";
5216 if ($spice_ticket) {
5217 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5218 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5223 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5224 if !$statefile && $conf->{balloon};
5226 foreach my $opt (keys %$conf) {
5227 next if $opt !~ m/^net\d+$/;
5228 my $nicconf = parse_net($conf->{$opt});
5229 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5233 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5234 path => "machine/peripheral/balloon0",
5235 property => "guest-stats-polling-interval",
5236 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5242 my ($vmid, $execute, %params) = @_;
5244 my $cmd = { execute => $execute, arguments => \%params };
5245 vm_qmp_command($vmid, $cmd);
5248 sub vm_mon_cmd_nocheck {
5249 my ($vmid, $execute, %params) = @_;
5251 my $cmd = { execute => $execute, arguments => \%params };
5252 vm_qmp_command($vmid, $cmd, 1);
5255 sub vm_qmp_command {
5256 my ($vmid, $cmd, $nocheck) = @_;
5261 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5262 $timeout = $cmd->{arguments}->{timeout};
5263 delete $cmd->{arguments}->{timeout};
5267 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5268 my $sname = qmp_socket($vmid);
5269 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5270 my $qmpclient = PVE::QMPClient->new();
5272 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5274 die "unable to open monitor socket\n";
5278 syslog("err", "VM $vmid qmp command failed - $err");
5285 sub vm_human_monitor_command {
5286 my ($vmid, $cmdline) = @_;
5291 execute => 'human-monitor-command
',
5292 arguments => { 'command-line
' => $cmdline},
5295 return vm_qmp_command($vmid, $cmd);
5298 sub vm_commandline {
5299 my ($storecfg, $vmid) = @_;
5301 my $conf = PVE::QemuConfig->load_config($vmid);
5303 my $defaults = load_defaults();
5305 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5307 return PVE::Tools::cmd2string($cmd);
5311 my ($vmid, $skiplock) = @_;
5313 PVE::QemuConfig->lock_config($vmid, sub {
5315 my $conf = PVE::QemuConfig->load_config($vmid);
5317 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5319 vm_mon_cmd($vmid, "system_reset");
5323 sub get_vm_volumes {
5327 foreach_volid($conf, sub {
5328 my ($volid, $attr) = @_;
5330 return if $volid =~ m|^/|;
5332 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5335 push @$vollist, $volid;
5341 sub vm_stop_cleanup {
5342 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5347 my $vollist = get_vm_volumes($conf);
5348 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5351 foreach my $ext (qw(mon qmp pid vnc qga)) {
5352 unlink "/var/run/qemu-server/${vmid}.$ext";
5355 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5357 warn $@ if $@; # avoid errors - just warn
5360 # Note: use $nockeck to skip tests if VM configuration file exists.
5361 # We need that when migration VMs to other nodes (files already moved)
5362 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5364 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5366 $force = 1 if !defined($force) && !$shutdown;
5369 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5370 kill 15, $pid if $pid;
5371 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5372 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5376 PVE
::QemuConfig-
>lock_config($vmid, sub {
5378 my $pid = check_running
($vmid, $nocheck);
5383 $conf = PVE
::QemuConfig-
>load_config($vmid);
5384 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5385 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5386 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5387 $timeout = $opts->{down
} if $opts->{down
};
5391 $timeout = 60 if !defined($timeout);
5395 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5396 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5398 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5401 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5408 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5413 if ($count >= $timeout) {
5415 warn "VM still running - terminating now with SIGTERM\n";
5418 die "VM quit/powerdown failed - got timeout\n";
5421 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5426 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5429 die "VM quit/powerdown failed\n";
5437 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5442 if ($count >= $timeout) {
5443 warn "VM still running - terminating now with SIGKILL\n";
5448 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5453 my ($vmid, $skiplock) = @_;
5455 PVE
::QemuConfig-
>lock_config($vmid, sub {
5457 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5459 PVE
::QemuConfig-
>check_lock($conf)
5460 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5462 vm_mon_cmd
($vmid, "stop");
5467 my ($vmid, $skiplock, $nocheck) = @_;
5469 PVE
::QemuConfig-
>lock_config($vmid, sub {
5471 my $res = vm_mon_cmd
($vmid, 'query-status');
5472 my $resume_cmd = 'cont';
5474 if ($res->{status
} && $res->{status
} eq 'suspended') {
5475 $resume_cmd = 'system_wakeup';
5480 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5482 PVE
::QemuConfig-
>check_lock($conf)
5483 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5485 vm_mon_cmd
($vmid, $resume_cmd);
5488 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5494 my ($vmid, $skiplock, $key) = @_;
5496 PVE
::QemuConfig-
>lock_config($vmid, sub {
5498 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5500 # there is no qmp command, so we use the human monitor command
5501 vm_human_monitor_command
($vmid, "sendkey $key");
5506 my ($storecfg, $vmid, $skiplock) = @_;
5508 PVE
::QemuConfig-
>lock_config($vmid, sub {
5510 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5512 if (!check_running
($vmid)) {
5513 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5515 die "VM $vmid is running - destroy failed\n";
5523 my ($filename, $buf) = @_;
5525 my $fh = IO
::File-
>new($filename, "w");
5526 return undef if !$fh;
5528 my $res = print $fh $buf;
5535 sub pci_device_info
{
5540 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5541 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5543 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5544 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5546 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5547 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5549 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5550 return undef if !defined($product) || $product !~ s/^0x//;
5555 product
=> $product,
5561 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5570 my $name = $dev->{name
};
5572 my $fn = "$pcisysfs/devices/$name/reset";
5574 return file_write
($fn, "1");
5577 sub pci_dev_bind_to_vfio
{
5580 my $name = $dev->{name
};
5582 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5584 if (!-d
$vfio_basedir) {
5585 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5587 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5589 my $testdir = "$vfio_basedir/$name";
5590 return 1 if -d
$testdir;
5592 my $data = "$dev->{vendor} $dev->{product}";
5593 return undef if !file_write
("$vfio_basedir/new_id", $data);
5595 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5596 if (!file_write
($fn, $name)) {
5597 return undef if -f
$fn;
5600 $fn = "$vfio_basedir/bind";
5601 if (! -d
$testdir) {
5602 return undef if !file_write
($fn, $name);
5608 sub pci_dev_group_bind_to_vfio
{
5611 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5613 if (!-d
$vfio_basedir) {
5614 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5616 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5618 # get IOMMU group devices
5619 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5620 my @devs = grep /^0000:/, readdir($D);
5623 foreach my $pciid (@devs) {
5624 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5626 # pci bridges, switches or root ports are not supported
5627 # they have a pci_bus subdirectory so skip them
5628 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5630 my $info = pci_device_info
($1);
5631 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5637 # vzdump restore implementaion
5639 sub tar_archive_read_firstfile
{
5640 my $archive = shift;
5642 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5644 # try to detect archive type first
5645 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5646 die "unable to open file '$archive'\n";
5647 my $firstfile = <$fh>;
5651 die "ERROR: archive contaions no data\n" if !$firstfile;
5657 sub tar_restore_cleanup
{
5658 my ($storecfg, $statfile) = @_;
5660 print STDERR
"starting cleanup\n";
5662 if (my $fd = IO
::File-
>new($statfile, "r")) {
5663 while (defined(my $line = <$fd>)) {
5664 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5667 if ($volid =~ m
|^/|) {
5668 unlink $volid || die 'unlink failed\n';
5670 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5672 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5674 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5676 print STDERR
"unable to parse line in statfile - $line";
5683 sub restore_archive
{
5684 my ($archive, $vmid, $user, $opts) = @_;
5686 my $format = $opts->{format
};
5689 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5690 $format = 'tar' if !$format;
5692 } elsif ($archive =~ m/\.tar$/) {
5693 $format = 'tar' if !$format;
5694 } elsif ($archive =~ m/.tar.lzo$/) {
5695 $format = 'tar' if !$format;
5697 } elsif ($archive =~ m/\.vma$/) {
5698 $format = 'vma' if !$format;
5699 } elsif ($archive =~ m/\.vma\.gz$/) {
5700 $format = 'vma' if !$format;
5702 } elsif ($archive =~ m/\.vma\.lzo$/) {
5703 $format = 'vma' if !$format;
5706 $format = 'vma' if !$format; # default
5709 # try to detect archive format
5710 if ($format eq 'tar') {
5711 return restore_tar_archive
($archive, $vmid, $user, $opts);
5713 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5717 sub restore_update_config_line
{
5718 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5720 return if $line =~ m/^\#qmdump\#/;
5721 return if $line =~ m/^\#vzdump\#/;
5722 return if $line =~ m/^lock:/;
5723 return if $line =~ m/^unused\d+:/;
5724 return if $line =~ m/^parent:/;
5725 return if $line =~ m/^template:/; # restored VM is never a template
5727 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5728 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5729 # try to convert old 1.X settings
5730 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5731 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5732 my ($model, $macaddr) = split(/\=/, $devconfig);
5733 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5736 bridge
=> "vmbr$ind",
5737 macaddr
=> $macaddr,
5739 my $netstr = print_net
($net);
5741 print $outfd "net$cookie->{netcount}: $netstr\n";
5742 $cookie->{netcount
}++;
5744 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5745 my ($id, $netstr) = ($1, $2);
5746 my $net = parse_net
($netstr);
5747 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5748 $netstr = print_net
($net);
5749 print $outfd "$id: $netstr\n";
5750 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5753 my $di = parse_drive
($virtdev, $value);
5754 if (defined($di->{backup
}) && !$di->{backup
}) {
5755 print $outfd "#$line";
5756 } elsif ($map->{$virtdev}) {
5757 delete $di->{format
}; # format can change on restore
5758 $di->{file
} = $map->{$virtdev};
5759 $value = print_drive
($vmid, $di);
5760 print $outfd "$virtdev: $value\n";
5764 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5766 if ($vmgenid ne '0') {
5767 # always generate a new vmgenid if there was a valid one setup
5768 $vmgenid = generate_uuid
();
5770 print $outfd "vmgenid: $vmgenid\n";
5771 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5772 my ($uuid, $uuid_str);
5773 UUID
::generate
($uuid);
5774 UUID
::unparse
($uuid, $uuid_str);
5775 my $smbios1 = parse_smbios1
($2);
5776 $smbios1->{uuid
} = $uuid_str;
5777 print $outfd $1.print_smbios1
($smbios1)."\n";
5784 my ($cfg, $vmid) = @_;
5786 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5788 my $volid_hash = {};
5789 foreach my $storeid (keys %$info) {
5790 foreach my $item (@{$info->{$storeid}}) {
5791 next if !($item->{volid
} && $item->{size
});
5792 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5793 $volid_hash->{$item->{volid
}} = $item;
5800 sub is_volume_in_use
{
5801 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5803 my $path = PVE
::Storage
::path
($storecfg, $volid);
5805 my $scan_config = sub {
5806 my ($cref, $snapname) = @_;
5808 foreach my $key (keys %$cref) {
5809 my $value = $cref->{$key};
5810 if (is_valid_drivename
($key)) {
5811 next if $skip_drive && $key eq $skip_drive;
5812 my $drive = parse_drive
($key, $value);
5813 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5814 return 1 if $volid eq $drive->{file
};
5815 if ($drive->{file
} =~ m!^/!) {
5816 return 1 if $drive->{file
} eq $path;
5818 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5820 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5822 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5830 return 1 if &$scan_config($conf);
5834 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5835 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5841 sub update_disksize
{
5842 my ($vmid, $conf, $volid_hash) = @_;
5845 my $prefix = "VM $vmid:";
5847 # used and unused disks
5848 my $referenced = {};
5850 # Note: it is allowed to define multiple storages with same path (alias), so
5851 # we need to check both 'volid' and real 'path' (two different volid can point
5852 # to the same path).
5854 my $referencedpath = {};
5857 foreach my $opt (keys %$conf) {
5858 if (is_valid_drivename
($opt)) {
5859 my $drive = parse_drive
($opt, $conf->{$opt});
5860 my $volid = $drive->{file
};
5863 $referenced->{$volid} = 1;
5864 if ($volid_hash->{$volid} &&
5865 (my $path = $volid_hash->{$volid}->{path
})) {
5866 $referencedpath->{$path} = 1;
5869 next if drive_is_cdrom
($drive);
5870 next if !$volid_hash->{$volid};
5872 $drive->{size
} = $volid_hash->{$volid}->{size
};
5873 my $new = print_drive
($vmid, $drive);
5874 if ($new ne $conf->{$opt}) {
5876 $conf->{$opt} = $new;
5877 print "$prefix update disk '$opt' information.\n";
5882 # remove 'unusedX' entry if volume is used
5883 foreach my $opt (keys %$conf) {
5884 next if $opt !~ m/^unused\d+$/;
5885 my $volid = $conf->{$opt};
5886 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5887 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5888 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5890 delete $conf->{$opt};
5893 $referenced->{$volid} = 1;
5894 $referencedpath->{$path} = 1 if $path;
5897 foreach my $volid (sort keys %$volid_hash) {
5898 next if $volid =~ m/vm-$vmid-state-/;
5899 next if $referenced->{$volid};
5900 my $path = $volid_hash->{$volid}->{path
};
5901 next if !$path; # just to be sure
5902 next if $referencedpath->{$path};
5904 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5905 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5906 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5913 my ($vmid, $nolock, $dryrun) = @_;
5915 my $cfg = PVE
::Storage
::config
();
5917 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5918 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5919 foreach my $stor (keys %{$cfg->{ids
}}) {
5920 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5923 print "rescan volumes...\n";
5924 my $volid_hash = scan_volids
($cfg, $vmid);
5926 my $updatefn = sub {
5929 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5931 PVE
::QemuConfig-
>check_lock($conf);
5934 foreach my $volid (keys %$volid_hash) {
5935 my $info = $volid_hash->{$volid};
5936 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5939 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5941 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5944 if (defined($vmid)) {
5948 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5951 my $vmlist = config_list
();
5952 foreach my $vmid (keys %$vmlist) {
5956 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5962 sub restore_vma_archive
{
5963 my ($archive, $vmid, $user, $opts, $comp) = @_;
5965 my $readfrom = $archive;
5967 my $cfg = PVE
::Storage
::config
();
5969 my $bwlimit = $opts->{bwlimit
};
5971 my $dbg_cmdstring = '';
5972 my $add_pipe = sub {
5974 push @$commands, $cmd;
5975 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5976 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5981 if ($archive eq '-') {
5984 # If we use a backup from a PVE defined storage we also consider that
5985 # storage's rate limit:
5986 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5987 if (defined($volid)) {
5988 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5989 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5991 print STDERR
"applying read rate limit: $readlimit\n";
5992 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5993 $add_pipe->($cstream);
6000 if ($comp eq 'gzip') {
6001 $cmd = ['zcat', $readfrom];
6002 } elsif ($comp eq 'lzop') {
6003 $cmd = ['lzop', '-d', '-c', $readfrom];
6005 die "unknown compression method '$comp'\n";
6010 my $tmpdir = "/var/tmp/vzdumptmp$$";
6013 # disable interrupts (always do cleanups)
6017 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6019 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6020 POSIX
::mkfifo
($mapfifo, 0600);
6023 my $openfifo = sub {
6024 open($fifofh, '>', $mapfifo) || die $!;
6027 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6034 my $rpcenv = PVE
::RPCEnvironment
::get
();
6036 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6037 my $tmpfn = "$conffile.$$.tmp";
6039 # Note: $oldconf is undef if VM does not exists
6040 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6041 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6045 my $print_devmap = sub {
6046 my $virtdev_hash = {};
6048 my $cfgfn = "$tmpdir/qemu-server.conf";
6050 # we can read the config - that is already extracted
6051 my $fh = IO
::File-
>new($cfgfn, "r") ||
6052 "unable to read qemu-server.conf - $!\n";
6054 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6056 my $pve_firewall_dir = '/etc/pve/firewall';
6057 mkdir $pve_firewall_dir; # make sure the dir exists
6058 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6061 while (defined(my $line = <$fh>)) {
6062 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6063 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6064 die "archive does not contain data for drive '$virtdev'\n"
6065 if !$devinfo->{$devname};
6066 if (defined($opts->{storage
})) {
6067 $storeid = $opts->{storage
} || 'local';
6068 } elsif (!$storeid) {
6071 $format = 'raw' if !$format;
6072 $devinfo->{$devname}->{devname
} = $devname;
6073 $devinfo->{$devname}->{virtdev
} = $virtdev;
6074 $devinfo->{$devname}->{format
} = $format;
6075 $devinfo->{$devname}->{storeid
} = $storeid;
6077 # check permission on storage
6078 my $pool = $opts->{pool
}; # todo: do we need that?
6079 if ($user ne 'root@pam') {
6080 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6083 $storage_limits{$storeid} = $bwlimit;
6085 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6089 foreach my $key (keys %storage_limits) {
6090 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6092 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6093 $storage_limits{$key} = $limit * 1024;
6096 foreach my $devname (keys %$devinfo) {
6097 die "found no device mapping information for device '$devname'\n"
6098 if !$devinfo->{$devname}->{virtdev
};
6101 # create empty/temp config
6103 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6104 foreach_drive
($oldconf, sub {
6105 my ($ds, $drive) = @_;
6107 return if drive_is_cdrom
($drive);
6109 my $volid = $drive->{file
};
6111 return if !$volid || $volid =~ m
|^/|;
6113 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6114 return if !$path || !$owner || ($owner != $vmid);
6116 # Note: only delete disk we want to restore
6117 # other volumes will become unused
6118 if ($virtdev_hash->{$ds}) {
6119 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6126 # delete vmstate files
6127 # since after the restore we have no snapshots anymore
6128 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6129 my $snap = $oldconf->{snapshots
}->{$snapname};
6130 if ($snap->{vmstate
}) {
6131 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6140 foreach my $virtdev (sort keys %$virtdev_hash) {
6141 my $d = $virtdev_hash->{$virtdev};
6142 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6143 my $storeid = $d->{storeid
};
6144 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6147 if (my $limit = $storage_limits{$storeid}) {
6148 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6151 # test if requested format is supported
6152 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6153 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6154 $d->{format
} = $defFormat if !$supported;
6156 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6157 $d->{format
}, undef, $alloc_size);
6158 print STDERR
"new volume ID is '$volid'\n";
6159 $d->{volid
} = $volid;
6160 my $path = PVE
::Storage
::path
($cfg, $volid);
6162 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6164 my $write_zeros = 1;
6165 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6169 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6171 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6172 $map->{$virtdev} = $volid;
6175 $fh->seek(0, 0) || die "seek failed - $!\n";
6177 my $outfd = new IO
::File
($tmpfn, "w") ||
6178 die "unable to write config for VM $vmid\n";
6180 my $cookie = { netcount
=> 0 };
6181 while (defined(my $line = <$fh>)) {
6182 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6195 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6196 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6198 $oldtimeout = alarm($timeout);
6205 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6206 my ($dev_id, $size, $devname) = ($1, $2, $3);
6207 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6208 } elsif ($line =~ m/^CTIME: /) {
6209 # we correctly received the vma config, so we can disable
6210 # the timeout now for disk allocation (set to 10 minutes, so
6211 # that we always timeout if something goes wrong)
6214 print $fifofh "done\n";
6215 my $tmp = $oldtimeout || 0;
6216 $oldtimeout = undef;
6222 print "restore vma archive: $dbg_cmdstring\n";
6223 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6227 alarm($oldtimeout) if $oldtimeout;
6230 foreach my $devname (keys %$devinfo) {
6231 my $volid = $devinfo->{$devname}->{volid
};
6232 push @$vollist, $volid if $volid;
6235 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6243 foreach my $devname (keys %$devinfo) {
6244 my $volid = $devinfo->{$devname}->{volid
};
6247 if ($volid =~ m
|^/|) {
6248 unlink $volid || die 'unlink failed\n';
6250 PVE
::Storage
::vdisk_free
($cfg, $volid);
6252 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6254 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6261 rename($tmpfn, $conffile) ||
6262 die "unable to commit configuration file '$conffile'\n";
6264 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6266 eval { rescan
($vmid, 1); };
6270 sub restore_tar_archive
{
6271 my ($archive, $vmid, $user, $opts) = @_;
6273 if ($archive ne '-') {
6274 my $firstfile = tar_archive_read_firstfile
($archive);
6275 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6276 if $firstfile ne 'qemu-server.conf';
6279 my $storecfg = PVE
::Storage
::config
();
6281 # destroy existing data - keep empty config
6282 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6283 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6285 my $tocmd = "/usr/lib/qemu-server/qmextract";
6287 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6288 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6289 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6290 $tocmd .= ' --info' if $opts->{info
};
6292 # tar option "xf" does not autodetect compression when read from STDIN,
6293 # so we pipe to zcat
6294 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6295 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6297 my $tmpdir = "/var/tmp/vzdumptmp$$";
6300 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6301 local $ENV{VZDUMP_VMID
} = $vmid;
6302 local $ENV{VZDUMP_USER
} = $user;
6304 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6305 my $tmpfn = "$conffile.$$.tmp";
6307 # disable interrupts (always do cleanups)
6311 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6319 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6321 if ($archive eq '-') {
6322 print "extracting archive from STDIN\n";
6323 run_command
($cmd, input
=> "<&STDIN");
6325 print "extracting archive '$archive'\n";
6329 return if $opts->{info
};
6333 my $statfile = "$tmpdir/qmrestore.stat";
6334 if (my $fd = IO
::File-
>new($statfile, "r")) {
6335 while (defined (my $line = <$fd>)) {
6336 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6337 $map->{$1} = $2 if $1;
6339 print STDERR
"unable to parse line in statfile - $line\n";
6345 my $confsrc = "$tmpdir/qemu-server.conf";
6347 my $srcfd = new IO
::File
($confsrc, "r") ||
6348 die "unable to open file '$confsrc'\n";
6350 my $outfd = new IO
::File
($tmpfn, "w") ||
6351 die "unable to write config for VM $vmid\n";
6353 my $cookie = { netcount
=> 0 };
6354 while (defined (my $line = <$srcfd>)) {
6355 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6367 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6374 rename $tmpfn, $conffile ||
6375 die "unable to commit configuration file '$conffile'\n";
6377 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6379 eval { rescan
($vmid, 1); };
6383 sub foreach_storage_used_by_vm
{
6384 my ($conf, $func) = @_;
6388 foreach_drive
($conf, sub {
6389 my ($ds, $drive) = @_;
6390 return if drive_is_cdrom
($drive);
6392 my $volid = $drive->{file
};
6394 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6395 $sidhash->{$sid} = $sid if $sid;
6398 foreach my $sid (sort keys %$sidhash) {
6403 sub do_snapshots_with_qemu
{
6404 my ($storecfg, $volid) = @_;
6406 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6408 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6409 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6413 if ($volid =~ m/\.(qcow2|qed)$/){
6420 sub qga_check_running
{
6421 my ($vmid, $nowarn) = @_;
6423 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6425 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6431 sub template_create
{
6432 my ($vmid, $conf, $disk) = @_;
6434 my $storecfg = PVE
::Storage
::config
();
6436 foreach_drive
($conf, sub {
6437 my ($ds, $drive) = @_;
6439 return if drive_is_cdrom
($drive);
6440 return if $disk && $ds ne $disk;
6442 my $volid = $drive->{file
};
6443 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6445 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6446 $drive->{file
} = $voliddst;
6447 $conf->{$ds} = print_drive
($vmid, $drive);
6448 PVE
::QemuConfig-
>write_config($vmid, $conf);
6452 sub qemu_img_convert
{
6453 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6455 my $storecfg = PVE
::Storage
::config
();
6456 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6457 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6459 if ($src_storeid && $dst_storeid) {
6461 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6463 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6464 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6466 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6467 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6469 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6470 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6473 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6474 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6475 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6476 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6477 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6478 if ($is_zero_initialized) {
6479 push @$cmd, "zeroinit:$dst_path";
6481 push @$cmd, $dst_path;
6486 if($line =~ m/\((\S+)\/100\
%\)/){
6488 my $transferred = int($size * $percent / 100);
6489 my $remaining = $size - $transferred;
6491 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6496 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6498 die "copy failed: $err" if $err;
6502 sub qemu_img_format
{
6503 my ($scfg, $volname) = @_;
6505 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6512 sub qemu_drive_mirror
{
6513 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6515 $jobs = {} if !$jobs;
6519 $jobs->{"drive-$drive"} = {};
6521 if ($dst_volid =~ /^nbd:/) {
6522 $qemu_target = $dst_volid;
6525 my $storecfg = PVE
::Storage
::config
();
6526 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6528 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6530 $format = qemu_img_format
($dst_scfg, $dst_volname);
6532 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6534 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6537 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6538 $opts->{format
} = $format if $format;
6540 print "drive mirror is starting for drive-$drive\n";
6542 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6545 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6546 die "mirroring error: $err";
6549 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6552 sub qemu_drive_mirror_monitor
{
6553 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6556 my $err_complete = 0;
6559 die "storage migration timed out\n" if $err_complete > 300;
6561 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6563 my $running_mirror_jobs = {};
6564 foreach my $stat (@$stats) {
6565 next if $stat->{type
} ne 'mirror';
6566 $running_mirror_jobs->{$stat->{device
}} = $stat;
6569 my $readycounter = 0;
6571 foreach my $job (keys %$jobs) {
6573 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6574 print "$job : finished\n";
6575 delete $jobs->{$job};
6579 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6581 my $busy = $running_mirror_jobs->{$job}->{busy
};
6582 my $ready = $running_mirror_jobs->{$job}->{ready
};
6583 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6584 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6585 my $remaining = $total - $transferred;
6586 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6588 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6591 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6594 last if scalar(keys %$jobs) == 0;
6596 if ($readycounter == scalar(keys %$jobs)) {
6597 print "all mirroring jobs are ready \n";
6598 last if $skipcomplete; #do the complete later
6600 if ($vmiddst && $vmiddst != $vmid) {
6601 my $agent_running = $qga && qga_check_running
($vmid);
6602 if ($agent_running) {
6603 print "freeze filesystem\n";
6604 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6606 print "suspend vm\n";
6607 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6610 # if we clone a disk for a new target vm, we don't switch the disk
6611 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6613 if ($agent_running) {
6614 print "unfreeze filesystem\n";
6615 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6617 print "resume vm\n";
6618 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6624 foreach my $job (keys %$jobs) {
6625 # try to switch the disk if source and destination are on the same guest
6626 print "$job: Completing block job...\n";
6628 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6629 if ($@ =~ m/cannot be completed/) {
6630 print "$job: Block job cannot be completed, try again.\n";
6633 print "$job: Completed successfully.\n";
6634 $jobs->{$job}->{complete
} = 1;
6645 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6646 die "mirroring error: $err";
6651 sub qemu_blockjobs_cancel
{
6652 my ($vmid, $jobs) = @_;
6654 foreach my $job (keys %$jobs) {
6655 print "$job: Cancelling block job\n";
6656 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6657 $jobs->{$job}->{cancel
} = 1;
6661 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6663 my $running_jobs = {};
6664 foreach my $stat (@$stats) {
6665 $running_jobs->{$stat->{device
}} = $stat;
6668 foreach my $job (keys %$jobs) {
6670 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6671 print "$job: Done.\n";
6672 delete $jobs->{$job};
6676 last if scalar(keys %$jobs) == 0;
6683 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6684 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6689 print "create linked clone of drive $drivename ($drive->{file})\n";
6690 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6691 push @$newvollist, $newvolid;
6694 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6695 $storeid = $storage if $storage;
6697 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6698 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6700 print "create full clone of drive $drivename ($drive->{file})\n";
6702 if (drive_is_cloudinit
($drive)) {
6703 $name = "vm-$newvmid-cloudinit";
6704 # cloudinit only supports raw and qcow2 atm:
6705 if ($dst_format eq 'qcow2') {
6707 } elsif ($dst_format ne 'raw') {
6708 die "clone: unhandled format for cloudinit image\n";
6711 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6712 push @$newvollist, $newvolid;
6714 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6716 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6717 if (!$running || $snapname) {
6718 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6721 my $kvmver = get_running_qemu_version
($vmid);
6722 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6723 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6724 if $drive->{iothread
};
6727 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6731 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6734 $disk->{format
} = undef;
6735 $disk->{file
} = $newvolid;
6736 $disk->{size
} = $size;
6741 # this only works if VM is running
6742 sub get_current_qemu_machine
{
6745 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6746 my $res = vm_qmp_command
($vmid, $cmd);
6748 my ($current, $default);
6749 foreach my $e (@$res) {
6750 $default = $e->{name
} if $e->{'is-default'};
6751 $current = $e->{name
} if $e->{'is-current'};
6754 # fallback to the default machine if current is not supported by qemu
6755 return $current || $default || 'pc';
6758 sub get_running_qemu_version
{
6760 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6761 my $res = vm_qmp_command
($vmid, $cmd);
6762 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6765 sub qemu_machine_feature_enabled
{
6766 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6771 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6773 $current_major = $3;
6774 $current_minor = $4;
6776 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6778 $current_major = $1;
6779 $current_minor = $2;
6782 return 1 if $current_major > $version_major ||
6783 ($current_major == $version_major &&
6784 $current_minor >= $version_minor);
6787 sub qemu_machine_pxe
{
6788 my ($vmid, $conf, $machine) = @_;
6790 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6792 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6799 sub qemu_use_old_bios_files
{
6800 my ($machine_type) = @_;
6802 return if !$machine_type;
6804 my $use_old_bios_files = undef;
6806 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6808 $use_old_bios_files = 1;
6810 my $kvmver = kvm_user_version
();
6811 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6812 # load new efi bios files on migration. So this hack is required to allow
6813 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6814 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6815 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6818 return ($use_old_bios_files, $machine_type);
6821 sub create_efidisk
($$$$$) {
6822 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6824 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6825 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6827 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6828 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6829 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6831 my $path = PVE
::Storage
::path
($storecfg, $volid);
6833 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6835 die "Copying EFI vars image failed: $@" if $@;
6837 return ($volid, $vars_size);
6844 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6845 my (undef, $id, $function) = @_;
6846 my $res = { id
=> $id, function
=> $function};
6847 push @{$devices->{$id}}, $res;
6850 # Entries should be sorted by functions.
6851 foreach my $id (keys %$devices) {
6852 my $dev = $devices->{$id};
6853 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6859 sub vm_iothreads_list
{
6862 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6865 foreach my $iothread (@$res) {
6866 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6873 my ($conf, $drive) = @_;
6877 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6879 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6885 my $controller = int($drive->{index} / $maxdev);
6886 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6888 return ($maxdev, $controller, $controller_prefix);
6891 sub add_hyperv_enlightenments
{
6892 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6894 return if $winversion < 6;
6895 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6897 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6899 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6900 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6901 push @$cpuFlags , 'hv_vapic';
6902 push @$cpuFlags , 'hv_time';
6904 push @$cpuFlags , 'hv_spinlocks=0xffff';
6907 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6908 push @$cpuFlags , 'hv_reset';
6909 push @$cpuFlags , 'hv_vpindex';
6910 push @$cpuFlags , 'hv_runtime';
6913 if ($winversion >= 7) {
6914 push @$cpuFlags , 'hv_relaxed';
6916 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6917 push @$cpuFlags , 'hv_synic';
6918 push @$cpuFlags , 'hv_stimer';
6923 sub windows_version
{
6926 return 0 if !$ostype;
6930 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6932 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6934 } elsif ($ostype =~ m/^win(\d+)$/) {
6941 sub resolve_dst_disk_format
{
6942 my ($storecfg, $storeid, $src_volname, $format) = @_;
6943 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6946 # if no target format is specified, use the source disk format as hint
6948 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6949 $format = qemu_img_format
($scfg, $src_volname);
6955 # test if requested format is supported - else use default
6956 my $supported = grep { $_ eq $format } @$validFormats;
6957 $format = $defFormat if !$supported;
6961 sub resolve_first_disk
{
6963 my @disks = PVE
::QemuServer
::valid_drive_names
();
6965 foreach my $ds (reverse @disks) {
6966 next if !$conf->{$ds};
6967 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6968 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6975 my ($uuid, $uuid_str);
6976 UUID
::generate
($uuid);
6977 UUID
::unparse
($uuid, $uuid_str);
6981 sub generate_smbios1_uuid
{
6982 return "uuid=".generate_uuid
();
6988 vm_mon_cmd
($vmid, 'nbd-server-stop');
6991 # bash completion helper
6993 sub complete_backup_archives
{
6994 my ($cmdname, $pname, $cvalue) = @_;
6996 my $cfg = PVE
::Storage
::config
();
7000 if ($cvalue =~ m/^([^:]+):/) {
7004 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7007 foreach my $id (keys %$data) {
7008 foreach my $item (@{$data->{$id}}) {
7009 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7010 push @$res, $item->{volid
} if defined($item->{volid
});
7017 my $complete_vmid_full = sub {
7020 my $idlist = vmstatus
();
7024 foreach my $id (keys %$idlist) {
7025 my $d = $idlist->{$id};
7026 if (defined($running)) {
7027 next if $d->{template
};
7028 next if $running && $d->{status
} ne 'running';
7029 next if !$running && $d->{status
} eq 'running';
7038 return &$complete_vmid_full();
7041 sub complete_vmid_stopped
{
7042 return &$complete_vmid_full(0);
7045 sub complete_vmid_running
{
7046 return &$complete_vmid_full(1);
7049 sub complete_storage
{
7051 my $cfg = PVE
::Storage
::config
();
7052 my $ids = $cfg->{ids
};
7055 foreach my $sid (keys %$ids) {
7056 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7057 next if !$ids->{$sid}->{content
}->{images
};