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 if (is_native
($arch)) {
1954 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1957 my $vmname = $conf->{name
} || "vm$vmid";
1960 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1962 if ($net->{bridge
}) {
1963 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1965 $netdev = "type=user,id=$netid,hostname=$vmname";
1968 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1974 sub print_cpu_device
{
1975 my ($conf, $id) = @_;
1977 my $kvm = $conf->{kvm
} // 1;
1978 my $cpu = $kvm ?
"kvm64" : "qemu64";
1979 if (my $cputype = $conf->{cpu
}) {
1980 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1981 or die "Cannot parse cpu description: $cputype\n";
1982 $cpu = $cpuconf->{cputype
};
1985 my $cores = $conf->{cores
} || 1;
1987 my $current_core = ($id - 1) % $cores;
1988 my $current_socket = int(($id - 1 - $current_core)/$cores);
1990 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1994 'cirrus' => 'cirrus-vga',
1996 'vmware' => 'vmware-svga',
1997 'virtio' => 'virtio-vga',
2000 sub print_vga_device
{
2001 my ($conf, $vga, $id, $qxlnum, $bridges) = @_;
2003 my $type = $vga_map->{$vga->{type
}};
2004 my $vgamem_mb = $vga->{memory
};
2006 $type = $id ?
'qxl' : 'qxl-vga';
2008 die "no devicetype for $vga->{type}\n" if !$type;
2012 if ($vga->{type
} eq 'virtio') {
2013 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2014 $memory = ",max_hostmem=$bytes";
2016 # from https://www.spice-space.org/multiple-monitors.html
2017 $memory = ",vgamem_mb=$vga->{memory}";
2018 my $ram = $vgamem_mb * 4;
2019 my $vram = $vgamem_mb * 2;
2020 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2022 $memory = ",vgamem_mb=$vga->{memory}";
2024 } elsif ($qxlnum && $id) {
2025 $memory = ",ram_size=67108864,vram_size=33554432";
2028 my $q35 = machine_type_is_q35
($conf);
2029 my $vgaid = "vga" . ($id // '');
2032 if ($q35 && $vgaid eq 'vga') {
2033 # the first display uses pcie.0 bus on q35 machines
2034 $pciaddr = print_pcie_addr
($vgaid, $bridges);
2036 $pciaddr = print_pci_addr
($vgaid, $bridges);
2039 return "$type,id=${vgaid}${memory}${pciaddr}";
2042 sub drive_is_cloudinit
{
2044 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2047 sub drive_is_cdrom
{
2048 my ($drive, $exclude_cloudinit) = @_;
2050 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2052 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2056 sub parse_number_sets
{
2059 foreach my $part (split(/;/, $set)) {
2060 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2061 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2062 push @$res, [ $1, $2 ];
2064 die "invalid range: $part\n";
2073 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2074 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2075 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2082 return undef if !$value;
2084 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2086 my @idlist = split(/;/, $res->{host
});
2087 delete $res->{host
};
2088 foreach my $id (@idlist) {
2089 if ($id =~ /^$PCIRE$/) {
2091 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
2093 my $pcidevices = lspci
($1);
2094 $res->{pciid
} = $pcidevices->{$1};
2097 # should have been caught by parse_property_string already
2098 die "failed to parse PCI id: $id\n";
2104 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2108 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2113 if (!defined($res->{macaddr
})) {
2114 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2115 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2120 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2121 sub parse_ipconfig
{
2124 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2130 if ($res->{gw
} && !$res->{ip
}) {
2131 warn 'gateway specified without specifying an IP address';
2134 if ($res->{gw6
} && !$res->{ip6
}) {
2135 warn 'IPv6 gateway specified without specifying an IPv6 address';
2138 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2139 warn 'gateway specified together with DHCP';
2142 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2144 warn "IPv6 gateway specified together with $res->{ip6} address";
2148 if (!$res->{ip
} && !$res->{ip6
}) {
2149 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2158 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2161 sub add_random_macs
{
2162 my ($settings) = @_;
2164 foreach my $opt (keys %$settings) {
2165 next if $opt !~ m/^net(\d+)$/;
2166 my $net = parse_net
($settings->{$opt});
2168 $settings->{$opt} = print_net
($net);
2172 sub vm_is_volid_owner
{
2173 my ($storecfg, $vmid, $volid) = @_;
2175 if ($volid !~ m
|^/|) {
2177 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2178 if ($owner && ($owner == $vmid)) {
2186 sub split_flagged_list
{
2187 my $text = shift || '';
2188 $text =~ s/[,;]/ /g;
2190 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2193 sub join_flagged_list
{
2194 my ($how, $lst) = @_;
2195 join $how, map { $lst->{$_} . $_ } keys %$lst;
2198 sub vmconfig_delete_pending_option
{
2199 my ($conf, $key, $force) = @_;
2201 delete $conf->{pending
}->{$key};
2202 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2203 $pending_delete_hash->{$key} = $force ?
'!' : '';
2204 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2207 sub vmconfig_undelete_pending_option
{
2208 my ($conf, $key) = @_;
2210 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2211 delete $pending_delete_hash->{$key};
2213 if (%$pending_delete_hash) {
2214 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2216 delete $conf->{pending
}->{delete};
2220 sub vmconfig_register_unused_drive
{
2221 my ($storecfg, $vmid, $conf, $drive) = @_;
2223 if (drive_is_cloudinit
($drive)) {
2224 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2226 } elsif (!drive_is_cdrom
($drive)) {
2227 my $volid = $drive->{file
};
2228 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2229 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2234 sub vmconfig_cleanup_pending
{
2237 # remove pending changes when nothing changed
2239 foreach my $opt (keys %{$conf->{pending
}}) {
2240 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2242 delete $conf->{pending
}->{$opt};
2246 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2247 my $pending_delete_hash = {};
2248 while (my ($opt, $force) = each %$current_delete_hash) {
2249 if (defined($conf->{$opt})) {
2250 $pending_delete_hash->{$opt} = $force;
2256 if (%$pending_delete_hash) {
2257 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2259 delete $conf->{pending
}->{delete};
2265 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2269 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2270 format_description
=> 'UUID',
2271 description
=> "Set SMBIOS1 UUID.",
2277 format_description
=> 'string',
2278 description
=> "Set SMBIOS1 version.",
2284 format_description
=> 'string',
2285 description
=> "Set SMBIOS1 serial number.",
2291 format_description
=> 'string',
2292 description
=> "Set SMBIOS1 manufacturer.",
2298 format_description
=> 'string',
2299 description
=> "Set SMBIOS1 product ID.",
2305 format_description
=> 'string',
2306 description
=> "Set SMBIOS1 SKU string.",
2312 format_description
=> 'string',
2313 description
=> "Set SMBIOS1 family string.",
2321 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2328 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2331 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2333 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2334 sub verify_bootdisk
{
2335 my ($value, $noerr) = @_;
2337 return $value if is_valid_drivename
($value);
2339 return undef if $noerr;
2341 die "invalid boot disk '$value'\n";
2344 sub parse_watchdog
{
2347 return undef if !$value;
2349 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2354 sub parse_guest_agent
{
2357 return {} if !defined($value->{agent
});
2359 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2362 # if the agent is disabled ignore the other potentially set properties
2363 return {} if !$res->{enabled
};
2370 return {} if !$value;
2371 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2376 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2377 sub verify_usb_device
{
2378 my ($value, $noerr) = @_;
2380 return $value if parse_usb_device
($value);
2382 return undef if $noerr;
2384 die "unable to parse usb device\n";
2387 # add JSON properties for create and set function
2388 sub json_config_properties
{
2391 foreach my $opt (keys %$confdesc) {
2392 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2393 $prop->{$opt} = $confdesc->{$opt};
2399 # return copy of $confdesc_cloudinit to generate documentation
2400 sub cloudinit_config_properties
{
2402 return dclone
($confdesc_cloudinit);
2406 my ($key, $value) = @_;
2408 die "unknown setting '$key'\n" if !$confdesc->{$key};
2410 my $type = $confdesc->{$key}->{type
};
2412 if (!defined($value)) {
2413 die "got undefined value\n";
2416 if ($value =~ m/[\n\r]/) {
2417 die "property contains a line feed\n";
2420 if ($type eq 'boolean') {
2421 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2422 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2423 die "type check ('boolean') failed - got '$value'\n";
2424 } elsif ($type eq 'integer') {
2425 return int($1) if $value =~ m/^(\d+)$/;
2426 die "type check ('integer') failed - got '$value'\n";
2427 } elsif ($type eq 'number') {
2428 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2429 die "type check ('number') failed - got '$value'\n";
2430 } elsif ($type eq 'string') {
2431 if (my $fmt = $confdesc->{$key}->{format
}) {
2432 PVE
::JSONSchema
::check_format
($fmt, $value);
2435 $value =~ s/^\"(.*)\"$/$1/;
2438 die "internal error"
2442 sub check_iommu_support
{
2443 #fixme : need to check IOMMU support
2444 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2454 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2455 utime undef, undef, $conf;
2459 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2461 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2463 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2465 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2467 if ($conf->{template
}) {
2468 # check if any base image is still used by a linked clone
2469 foreach_drive
($conf, sub {
2470 my ($ds, $drive) = @_;
2472 return if drive_is_cdrom
($drive);
2474 my $volid = $drive->{file
};
2476 return if !$volid || $volid =~ m
|^/|;
2478 die "base volume '$volid' is still in use by linked cloned\n"
2479 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2484 # only remove disks owned by this VM
2485 foreach_drive
($conf, sub {
2486 my ($ds, $drive) = @_;
2488 return if drive_is_cdrom
($drive, 1);
2490 my $volid = $drive->{file
};
2492 return if !$volid || $volid =~ m
|^/|;
2494 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2495 return if !$path || !$owner || ($owner != $vmid);
2498 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2500 warn "Could not remove disk '$volid', check manually: $@" if $@;
2504 if ($keep_empty_config) {
2505 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2510 # also remove unused disk
2512 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2515 PVE
::Storage
::foreach_volid
($dl, sub {
2516 my ($volid, $sid, $volname, $d) = @_;
2517 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2526 sub parse_vm_config
{
2527 my ($filename, $raw) = @_;
2529 return undef if !defined($raw);
2532 digest
=> Digest
::SHA
::sha1_hex
($raw),
2537 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2538 || die "got strange filename '$filename'";
2546 my @lines = split(/\n/, $raw);
2547 foreach my $line (@lines) {
2548 next if $line =~ m/^\s*$/;
2550 if ($line =~ m/^\[PENDING\]\s*$/i) {
2551 $section = 'pending';
2552 if (defined($descr)) {
2554 $conf->{description
} = $descr;
2557 $conf = $res->{$section} = {};
2560 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2562 if (defined($descr)) {
2564 $conf->{description
} = $descr;
2567 $conf = $res->{snapshots
}->{$section} = {};
2571 if ($line =~ m/^\#(.*)\s*$/) {
2572 $descr = '' if !defined($descr);
2573 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2577 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2578 $descr = '' if !defined($descr);
2579 $descr .= PVE
::Tools
::decode_text
($2);
2580 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2581 $conf->{snapstate
} = $1;
2582 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2585 $conf->{$key} = $value;
2586 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2588 if ($section eq 'pending') {
2589 $conf->{delete} = $value; # we parse this later
2591 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2593 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2596 eval { $value = check_type
($key, $value); };
2598 warn "vm $vmid - unable to parse value of '$key' - $@";
2600 $key = 'ide2' if $key eq 'cdrom';
2601 my $fmt = $confdesc->{$key}->{format
};
2602 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2603 my $v = parse_drive
($key, $value);
2604 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2605 $v->{file
} = $volid;
2606 $value = print_drive
($vmid, $v);
2608 warn "vm $vmid - unable to parse value of '$key'\n";
2613 $conf->{$key} = $value;
2618 if (defined($descr)) {
2620 $conf->{description
} = $descr;
2622 delete $res->{snapstate
}; # just to be sure
2627 sub write_vm_config
{
2628 my ($filename, $conf) = @_;
2630 delete $conf->{snapstate
}; # just to be sure
2632 if ($conf->{cdrom
}) {
2633 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2634 $conf->{ide2
} = $conf->{cdrom
};
2635 delete $conf->{cdrom
};
2638 # we do not use 'smp' any longer
2639 if ($conf->{sockets
}) {
2640 delete $conf->{smp
};
2641 } elsif ($conf->{smp
}) {
2642 $conf->{sockets
} = $conf->{smp
};
2643 delete $conf->{cores
};
2644 delete $conf->{smp
};
2647 my $used_volids = {};
2649 my $cleanup_config = sub {
2650 my ($cref, $pending, $snapname) = @_;
2652 foreach my $key (keys %$cref) {
2653 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2654 $key eq 'snapstate' || $key eq 'pending';
2655 my $value = $cref->{$key};
2656 if ($key eq 'delete') {
2657 die "propertry 'delete' is only allowed in [PENDING]\n"
2659 # fixme: check syntax?
2662 eval { $value = check_type
($key, $value); };
2663 die "unable to parse value of '$key' - $@" if $@;
2665 $cref->{$key} = $value;
2667 if (!$snapname && is_valid_drivename
($key)) {
2668 my $drive = parse_drive
($key, $value);
2669 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2674 &$cleanup_config($conf);
2676 &$cleanup_config($conf->{pending
}, 1);
2678 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2679 die "internal error" if $snapname eq 'pending';
2680 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2683 # remove 'unusedX' settings if we re-add a volume
2684 foreach my $key (keys %$conf) {
2685 my $value = $conf->{$key};
2686 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2687 delete $conf->{$key};
2691 my $generate_raw_config = sub {
2692 my ($conf, $pending) = @_;
2696 # add description as comment to top of file
2697 if (defined(my $descr = $conf->{description
})) {
2699 foreach my $cl (split(/\n/, $descr)) {
2700 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2703 $raw .= "#\n" if $pending;
2707 foreach my $key (sort keys %$conf) {
2708 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2709 $raw .= "$key: $conf->{$key}\n";
2714 my $raw = &$generate_raw_config($conf);
2716 if (scalar(keys %{$conf->{pending
}})){
2717 $raw .= "\n[PENDING]\n";
2718 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2721 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2722 $raw .= "\n[$snapname]\n";
2723 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2733 # we use static defaults from our JSON schema configuration
2734 foreach my $key (keys %$confdesc) {
2735 if (defined(my $default = $confdesc->{$key}->{default})) {
2736 $res->{$key} = $default;
2744 my $vmlist = PVE
::Cluster
::get_vmlist
();
2746 return $res if !$vmlist || !$vmlist->{ids
};
2747 my $ids = $vmlist->{ids
};
2749 foreach my $vmid (keys %$ids) {
2750 my $d = $ids->{$vmid};
2751 next if !$d->{node
} || $d->{node
} ne $nodename;
2752 next if !$d->{type
} || $d->{type
} ne 'qemu';
2753 $res->{$vmid}->{exists} = 1;
2758 # test if VM uses local resources (to prevent migration)
2759 sub check_local_resources
{
2760 my ($conf, $noerr) = @_;
2764 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2765 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2767 foreach my $k (keys %$conf) {
2768 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2769 # sockets are safe: they will recreated be on the target side post-migrate
2770 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2771 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2774 die "VM uses local resources\n" if $loc_res && !$noerr;
2779 # check if used storages are available on all nodes (use by migrate)
2780 sub check_storage_availability
{
2781 my ($storecfg, $conf, $node) = @_;
2783 foreach_drive
($conf, sub {
2784 my ($ds, $drive) = @_;
2786 my $volid = $drive->{file
};
2789 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2792 # check if storage is available on both nodes
2793 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2794 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2798 # list nodes where all VM images are available (used by has_feature API)
2800 my ($conf, $storecfg) = @_;
2802 my $nodelist = PVE
::Cluster
::get_nodelist
();
2803 my $nodehash = { map { $_ => 1 } @$nodelist };
2804 my $nodename = PVE
::INotify
::nodename
();
2806 foreach_drive
($conf, sub {
2807 my ($ds, $drive) = @_;
2809 my $volid = $drive->{file
};
2812 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2814 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2815 if ($scfg->{disable
}) {
2817 } elsif (my $avail = $scfg->{nodes
}) {
2818 foreach my $node (keys %$nodehash) {
2819 delete $nodehash->{$node} if !$avail->{$node};
2821 } elsif (!$scfg->{shared
}) {
2822 foreach my $node (keys %$nodehash) {
2823 delete $nodehash->{$node} if $node ne $nodename
2833 my ($pidfile, $pid) = @_;
2835 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2839 return undef if !$line;
2840 my @param = split(/\0/, $line);
2842 my $cmd = $param[0];
2843 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2845 for (my $i = 0; $i < scalar (@param); $i++) {
2848 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2849 my $p = $param[$i+1];
2850 return 1 if $p && ($p eq $pidfile);
2859 my ($vmid, $nocheck, $node) = @_;
2861 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2863 die "unable to find configuration file for VM $vmid - no such machine\n"
2864 if !$nocheck && ! -f
$filename;
2866 my $pidfile = pidfile_name
($vmid);
2868 if (my $fd = IO
::File-
>new("<$pidfile")) {
2873 my $mtime = $st->mtime;
2874 if ($mtime > time()) {
2875 warn "file '$filename' modified in future\n";
2878 if ($line =~ m/^(\d+)$/) {
2880 if (check_cmdline
($pidfile, $pid)) {
2881 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2893 my $vzlist = config_list
();
2895 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2897 while (defined(my $de = $fd->read)) {
2898 next if $de !~ m/^(\d+)\.pid$/;
2900 next if !defined($vzlist->{$vmid});
2901 if (my $pid = check_running
($vmid)) {
2902 $vzlist->{$vmid}->{pid
} = $pid;
2910 my ($storecfg, $conf) = @_;
2912 my $bootdisk = $conf->{bootdisk
};
2913 return undef if !$bootdisk;
2914 return undef if !is_valid_drivename
($bootdisk);
2916 return undef if !$conf->{$bootdisk};
2918 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2919 return undef if !defined($drive);
2921 return undef if drive_is_cdrom
($drive);
2923 my $volid = $drive->{file
};
2924 return undef if !$volid;
2926 return $drive->{size
};
2929 our $vmstatus_return_properties = {
2930 vmid
=> get_standard_option
('pve-vmid'),
2932 description
=> "Qemu process status.",
2934 enum
=> ['stopped', 'running'],
2937 description
=> "Maximum memory in bytes.",
2940 renderer
=> 'bytes',
2943 description
=> "Root disk size in bytes.",
2946 renderer
=> 'bytes',
2949 description
=> "VM name.",
2954 description
=> "Qemu QMP agent status.",
2959 description
=> "PID of running qemu process.",
2964 description
=> "Uptime.",
2967 renderer
=> 'duration',
2970 description
=> "Maximum usable CPUs.",
2976 my $last_proc_pid_stat;
2978 # get VM status information
2979 # This must be fast and should not block ($full == false)
2980 # We only query KVM using QMP if $full == true (this can be slow)
2982 my ($opt_vmid, $full) = @_;
2986 my $storecfg = PVE
::Storage
::config
();
2988 my $list = vzlist
();
2989 my $defaults = load_defaults
();
2991 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2993 my $cpucount = $cpuinfo->{cpus
} || 1;
2995 foreach my $vmid (keys %$list) {
2996 next if $opt_vmid && ($vmid ne $opt_vmid);
2998 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2999 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3001 my $d = { vmid
=> $vmid };
3002 $d->{pid
} = $list->{$vmid}->{pid
};
3004 # fixme: better status?
3005 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3007 my $size = disksize
($storecfg, $conf);
3008 if (defined($size)) {
3009 $d->{disk
} = 0; # no info available
3010 $d->{maxdisk
} = $size;
3016 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3017 * ($conf->{cores
} || $defaults->{cores
});
3018 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3019 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3021 $d->{name
} = $conf->{name
} || "VM $vmid";
3022 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3023 : $defaults->{memory
}*(1024*1024);
3025 if ($conf->{balloon
}) {
3026 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3027 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3028 : $defaults->{shares
};
3039 $d->{diskwrite
} = 0;
3041 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3043 $d->{serial
} = 1 if conf_has_serial
($conf);
3048 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3049 foreach my $dev (keys %$netdev) {
3050 next if $dev !~ m/^tap([1-9]\d*)i/;
3052 my $d = $res->{$vmid};
3055 $d->{netout
} += $netdev->{$dev}->{receive
};
3056 $d->{netin
} += $netdev->{$dev}->{transmit
};
3059 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3060 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3065 my $ctime = gettimeofday
;
3067 foreach my $vmid (keys %$list) {
3069 my $d = $res->{$vmid};
3070 my $pid = $d->{pid
};
3073 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3074 next if !$pstat; # not running
3076 my $used = $pstat->{utime} + $pstat->{stime
};
3078 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3080 if ($pstat->{vsize
}) {
3081 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3084 my $old = $last_proc_pid_stat->{$pid};
3086 $last_proc_pid_stat->{$pid} = {
3094 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3096 if ($dtime > 1000) {
3097 my $dutime = $used - $old->{used
};
3099 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3100 $last_proc_pid_stat->{$pid} = {
3106 $d->{cpu
} = $old->{cpu
};
3110 return $res if !$full;
3112 my $qmpclient = PVE
::QMPClient-
>new();
3114 my $ballooncb = sub {
3115 my ($vmid, $resp) = @_;
3117 my $info = $resp->{'return'};
3118 return if !$info->{max_mem
};
3120 my $d = $res->{$vmid};
3122 # use memory assigned to VM
3123 $d->{maxmem
} = $info->{max_mem
};
3124 $d->{balloon
} = $info->{actual
};
3126 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3127 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3128 $d->{freemem
} = $info->{free_mem
};
3131 $d->{ballooninfo
} = $info;
3134 my $blockstatscb = sub {
3135 my ($vmid, $resp) = @_;
3136 my $data = $resp->{'return'} || [];
3137 my $totalrdbytes = 0;
3138 my $totalwrbytes = 0;
3140 for my $blockstat (@$data) {
3141 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3142 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3144 $blockstat->{device
} =~ s/drive-//;
3145 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3147 $res->{$vmid}->{diskread
} = $totalrdbytes;
3148 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3151 my $statuscb = sub {
3152 my ($vmid, $resp) = @_;
3154 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3155 # this fails if ballon driver is not loaded, so this must be
3156 # the last commnand (following command are aborted if this fails).
3157 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3159 my $status = 'unknown';
3160 if (!defined($status = $resp->{'return'}->{status
})) {
3161 warn "unable to get VM status\n";
3165 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3168 foreach my $vmid (keys %$list) {
3169 next if $opt_vmid && ($vmid ne $opt_vmid);
3170 next if !$res->{$vmid}->{pid
}; # not running
3171 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3174 $qmpclient->queue_execute(undef, 2);
3176 foreach my $vmid (keys %$list) {
3177 next if $opt_vmid && ($vmid ne $opt_vmid);
3178 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3185 my ($conf, $func, @param) = @_;
3187 foreach my $ds (valid_drive_names
()) {
3188 next if !defined($conf->{$ds});
3190 my $drive = parse_drive
($ds, $conf->{$ds});
3193 &$func($ds, $drive, @param);
3198 my ($conf, $func, @param) = @_;
3202 my $test_volid = sub {
3203 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3207 $volhash->{$volid}->{cdrom
} //= 1;
3208 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3210 $volhash->{$volid}->{replicate
} //= 0;
3211 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3213 $volhash->{$volid}->{shared
} //= 0;
3214 $volhash->{$volid}->{shared
} = 1 if $shared;
3216 $volhash->{$volid}->{referenced_in_config
} //= 0;
3217 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3219 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3220 if defined($snapname);
3223 foreach_drive
($conf, sub {
3224 my ($ds, $drive) = @_;
3225 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3228 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3229 my $snap = $conf->{snapshots
}->{$snapname};
3230 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3231 foreach_drive
($snap, sub {
3232 my ($ds, $drive) = @_;
3233 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3237 foreach my $volid (keys %$volhash) {
3238 &$func($volid, $volhash->{$volid}, @param);
3242 sub conf_has_serial
{
3245 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3246 if ($conf->{"serial$i"}) {
3254 sub vga_conf_has_spice
{
3257 my $vgaconf = parse_vga
($vga);
3258 my $vgatype = $vgaconf->{type
};
3259 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3264 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3265 sub get_host_arch
() {
3266 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3272 return get_host_arch
() eq $arch;
3275 my $default_machines = {
3280 sub get_basic_machine_info
{
3281 my ($conf, $forcemachine) = @_;
3283 my $arch = $conf->{arch
} // get_host_arch
();
3284 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3285 return ($arch, $machine);
3288 sub get_ovmf_files
($) {
3291 my $ovmf = $OVMF->{$arch}
3292 or die "no OVMF images known for architecture '$arch'\n";
3298 aarch64
=> '/usr/bin/qemu-system-aarch64',
3299 x86_64
=> '/usr/bin/qemu-system-x86_64',
3301 sub get_command_for_arch
($) {
3303 return '/usr/bin/kvm' if is_native
($arch);
3305 my $cmd = $Arch2Qemu->{$arch}
3306 or die "don't know how to emulate architecture '$arch'\n";
3310 sub get_cpu_options
{
3311 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3314 my $ostype = $conf->{ostype
};
3316 my $cpu = $kvm ?
"kvm64" : "qemu64";
3317 if ($arch eq 'aarch64') {
3318 $cpu = 'cortex-a57';
3320 if (my $cputype = $conf->{cpu
}) {
3321 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3322 or die "Cannot parse cpu description: $cputype\n";
3323 $cpu = $cpuconf->{cputype
};
3324 $kvm_off = 1 if $cpuconf->{hidden
};
3326 if (defined(my $flags = $cpuconf->{flags
})) {
3327 push @$cpuFlags, split(";", $flags);
3331 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3333 push @$cpuFlags , '-x2apic'
3334 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3336 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3338 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3340 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3342 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3343 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3346 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3348 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3350 push @$cpuFlags, 'kvm=off' if $kvm_off;
3352 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3353 push @$cpuFlags, "vendor=${cpu_vendor}"
3354 if $cpu_vendor ne 'default';
3355 } elsif ($arch ne 'aarch64') {
3356 die "internal error"; # should not happen
3359 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3361 return ('-cpu', $cpu);
3364 sub config_to_command
{
3365 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3368 my $globalFlags = [];
3369 my $machineFlags = [];
3374 my $kvmver = kvm_user_version
();
3375 my $vernum = 0; # unknown
3376 my $ostype = $conf->{ostype
};
3377 my $winversion = windows_version
($ostype);
3378 my $kvm = $conf->{kvm
};
3380 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3381 $kvm //= 1 if is_native
($arch);
3384 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3385 if !defined kvm_version
();
3388 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3389 $vernum = $1*1000000+$2*1000;
3390 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3391 $vernum = $1*1000000+$2*1000+$3;
3394 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3396 my $have_ovz = -f
'/proc/vz/vestat';
3398 my $q35 = machine_type_is_q35
($conf);
3399 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3400 my $use_old_bios_files = undef;
3401 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3403 my $cpuunits = defined($conf->{cpuunits
}) ?
3404 $conf->{cpuunits
} : $defaults->{cpuunits
};
3406 push @$cmd, get_command_for_arch
($arch);
3408 push @$cmd, '-id', $vmid;
3410 my $vmname = $conf->{name
} || "vm$vmid";
3412 push @$cmd, '-name', $vmname;
3416 my $qmpsocket = qmp_socket
($vmid);
3417 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3418 push @$cmd, '-mon', "chardev=qmp,mode=control";
3420 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3421 my $eventsocket = qmp_socket
($vmid, 0, 'event');
3422 push @$cmd, '-chardev', "socket,id=qmp-event,path=$eventsocket,server,nowait";
3423 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3426 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3428 push @$cmd, '-daemonize';
3430 if ($conf->{smbios1
}) {
3431 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3434 if ($conf->{vmgenid
}) {
3435 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3438 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3439 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3440 die "uefi base image not found\n" if ! -f
$ovmf_code;
3444 if (my $efidisk = $conf->{efidisk0
}) {
3445 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3446 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3447 $format = $d->{format
};
3449 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3450 if (!defined($format)) {
3451 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3452 $format = qemu_img_format
($scfg, $volname);
3456 die "efidisk format must be specified\n"
3457 if !defined($format);
3460 warn "no efidisk configured! Using temporary efivars disk.\n";
3461 $path = "/tmp/$vmid-ovmf.fd";
3462 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3466 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3467 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3471 # add usb controllers
3472 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3473 push @$devices, @usbcontrollers if @usbcontrollers;
3474 my $vga = parse_vga
($conf->{vga
});
3476 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3477 $vga->{type
} = 'qxl' if $qxlnum;
3479 if (!$vga->{type
}) {
3480 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3481 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3483 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3487 # enable absolute mouse coordinates (needed by vnc)
3489 if (defined($conf->{tablet
})) {
3490 $tablet = $conf->{tablet
};
3492 $tablet = $defaults->{tablet
};
3493 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3494 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3497 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3500 my $gpu_passthrough;
3503 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3504 my $d = parse_hostpci
($conf->{"hostpci$i"});
3507 my $pcie = $d->{pcie
};
3509 die "q35 machine model is not enabled" if !$q35;
3510 $pciaddr = print_pcie_addr
("hostpci$i");
3512 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3515 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3516 my $romfile = $d->{romfile
};
3519 if ($d->{'x-vga'}) {
3520 $xvga = ',x-vga=on';
3522 $vga->{type
} = 'none';
3523 $gpu_passthrough = 1;
3525 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3529 my $pcidevices = $d->{pciid
};
3530 my $multifunction = 1 if @$pcidevices > 1;
3533 foreach my $pcidevice (@$pcidevices) {
3535 my $id = "hostpci$i";
3536 $id .= ".$j" if $multifunction;
3537 my $addr = $pciaddr;
3538 $addr .= ".$j" if $multifunction;
3539 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3542 $devicestr .= "$rombar$xvga";
3543 $devicestr .= ",multifunction=on" if $multifunction;
3544 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3547 push @$devices, '-device', $devicestr;
3553 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3554 push @$devices, @usbdevices if @usbdevices;
3556 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3557 if (my $path = $conf->{"serial$i"}) {
3558 if ($path eq 'socket') {
3559 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3560 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3561 push @$devices, '-device', "isa-serial,chardev=serial$i";
3563 die "no such serial device\n" if ! -c
$path;
3564 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3565 push @$devices, '-device', "isa-serial,chardev=serial$i";
3571 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3572 if (my $path = $conf->{"parallel$i"}) {
3573 die "no such parallel device\n" if ! -c
$path;
3574 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3575 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3576 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3582 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3583 $sockets = $conf->{sockets
} if $conf->{sockets
};
3585 my $cores = $conf->{cores
} || 1;
3587 my $maxcpus = $sockets * $cores;
3589 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3591 my $allowed_vcpus = $cpuinfo->{cpus
};
3593 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3594 if ($allowed_vcpus < $maxcpus);
3596 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3598 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3599 for (my $i = 2; $i <= $vcpus; $i++) {
3600 my $cpustr = print_cpu_device
($conf,$i);
3601 push @$cmd, '-device', $cpustr;
3606 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3608 push @$cmd, '-nodefaults';
3610 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3612 my $bootindex_hash = {};
3614 foreach my $o (split(//, $bootorder)) {
3615 $bootindex_hash->{$o} = $i*100;
3619 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3621 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3623 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3625 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3626 push @$devices, '-device', print_vga_device
($conf, $vga, undef, $qxlnum, $bridges);
3627 my $socket = vnc_socket
($vmid);
3628 push @$cmd, '-vnc', "unix:$socket,x509,password";
3630 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3631 push @$cmd, '-nographic';
3635 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3637 my $useLocaltime = $conf->{localtime};
3639 if ($winversion >= 5) { # windows
3640 $useLocaltime = 1 if !defined($conf->{localtime});
3642 # use time drift fix when acpi is enabled
3643 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3644 $tdf = 1 if !defined($conf->{tdf
});
3648 if ($winversion >= 6) {
3649 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3650 push @$cmd, '-no-hpet';
3653 push @$rtcFlags, 'driftfix=slew' if $tdf;
3656 push @$machineFlags, 'accel=tcg';
3659 if ($machine_type) {
3660 push @$machineFlags, "type=${machine_type}";
3663 if ($conf->{startdate
}) {
3664 push @$rtcFlags, "base=$conf->{startdate}";
3665 } elsif ($useLocaltime) {
3666 push @$rtcFlags, 'base=localtime';
3669 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3671 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3673 push @$cmd, '-S' if $conf->{freeze
};
3675 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3678 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3679 #push @$cmd, '-soundhw', 'es1370';
3680 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3682 if (parse_guest_agent
($conf)->{enabled
}) {
3683 my $qgasocket = qmp_socket
($vmid, 1);
3684 my $pciaddr = print_pci_addr
("qga0", $bridges);
3685 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3686 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3687 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3695 for(my $i = 1; $i < $qxlnum; $i++){
3696 push @$devices, '-device', print_vga_device
($conf, $vga, $i, $qxlnum, $bridges);
3699 # assume other OS works like Linux
3700 my ($ram, $vram) = ("134217728", "67108864");
3701 if ($vga->{memory
}) {
3702 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3703 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3705 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3706 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3710 my $pciaddr = print_pci_addr
("spice", $bridges);
3712 my $nodename = PVE
::INotify
::nodename
();
3713 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3714 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3715 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3716 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3717 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3719 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3721 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3722 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3723 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3726 # enable balloon by default, unless explicitly disabled
3727 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3728 $pciaddr = print_pci_addr
("balloon0", $bridges);
3729 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3732 if ($conf->{watchdog
}) {
3733 my $wdopts = parse_watchdog
($conf->{watchdog
});
3734 $pciaddr = print_pci_addr
("watchdog", $bridges);
3735 my $watchdog = $wdopts->{model
} || 'i6300esb';
3736 push @$devices, '-device', "$watchdog$pciaddr";
3737 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3741 my $scsicontroller = {};
3742 my $ahcicontroller = {};
3743 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3745 # Add iscsi initiator name if available
3746 if (my $initiator = get_initiator_name
()) {
3747 push @$devices, '-iscsi', "initiator-name=$initiator";
3750 foreach_drive
($conf, sub {
3751 my ($ds, $drive) = @_;
3753 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3754 push @$vollist, $drive->{file
};
3757 # ignore efidisk here, already added in bios/fw handling code above
3758 return if $drive->{interface
} eq 'efidisk';
3760 $use_virtio = 1 if $ds =~ m/^virtio/;
3762 if (drive_is_cdrom
($drive)) {
3763 if ($bootindex_hash->{d
}) {
3764 $drive->{bootindex
} = $bootindex_hash->{d
};
3765 $bootindex_hash->{d
} += 1;
3768 if ($bootindex_hash->{c
}) {
3769 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3770 $bootindex_hash->{c
} += 1;
3774 if($drive->{interface
} eq 'virtio'){
3775 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3778 if ($drive->{interface
} eq 'scsi') {
3780 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3782 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3783 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3786 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3787 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3788 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3789 } elsif ($drive->{iothread
}) {
3790 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3794 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3795 $queues = ",num_queues=$drive->{queues}";
3798 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3799 $scsicontroller->{$controller}=1;
3802 if ($drive->{interface
} eq 'sata') {
3803 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3804 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3805 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3806 $ahcicontroller->{$controller}=1;
3809 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3810 push @$devices, '-drive',$drive_cmd;
3811 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3814 for (my $i = 0; $i < $MAX_NETS; $i++) {
3815 next if !$conf->{"net$i"};
3816 my $d = parse_net
($conf->{"net$i"});
3819 $use_virtio = 1 if $d->{model
} eq 'virtio';
3821 if ($bootindex_hash->{n
}) {
3822 $d->{bootindex
} = $bootindex_hash->{n
};
3823 $bootindex_hash->{n
} += 1;
3826 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3827 push @$devices, '-netdev', $netdevfull;
3829 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3830 push @$devices, '-device', $netdevicefull;
3835 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3840 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3842 while (my ($k, $v) = each %$bridges) {
3843 $pciaddr = print_pci_addr
("pci.$k");
3844 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3849 if ($conf->{args
}) {
3850 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3854 push @$cmd, @$devices;
3855 push @$cmd, '-rtc', join(',', @$rtcFlags)
3856 if scalar(@$rtcFlags);
3857 push @$cmd, '-machine', join(',', @$machineFlags)
3858 if scalar(@$machineFlags);
3859 push @$cmd, '-global', join(',', @$globalFlags)
3860 if scalar(@$globalFlags);
3862 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3867 return "${var_run_tmpdir}/$vmid.vnc";
3873 my $res = vm_mon_cmd
($vmid, 'query-spice');
3875 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3879 my ($vmid, $qga, $name) = @_;
3880 my $sockettype = $qga ?
'qga' : 'qmp';
3881 my $ext = $name ?
'-'.$name : '';
3882 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3887 return "${var_run_tmpdir}/$vmid.pid";
3890 sub vm_devices_list
{
3893 my $res = vm_mon_cmd
($vmid, 'query-pci');
3894 my $devices_to_check = [];
3896 foreach my $pcibus (@$res) {
3897 push @$devices_to_check, @{$pcibus->{devices
}},
3900 while (@$devices_to_check) {
3902 for my $d (@$devices_to_check) {
3903 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3904 next if !$d->{'pci_bridge'};
3906 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3907 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3909 $devices_to_check = $to_check;
3912 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3913 foreach my $block (@$resblock) {
3914 if($block->{device
} =~ m/^drive-(\S+)/){
3919 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3920 foreach my $mice (@$resmice) {
3921 if ($mice->{name
} eq 'QEMU HID Tablet') {
3922 $devices->{tablet
} = 1;
3927 # for usb devices there is no query-usb
3928 # but we can iterate over the entries in
3929 # qom-list path=/machine/peripheral
3930 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3931 foreach my $per (@$resperipheral) {
3932 if ($per->{name
} =~ m/^usb\d+$/) {
3933 $devices->{$per->{name
}} = 1;
3941 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3943 my $q35 = machine_type_is_q35
($conf);
3945 my $devices_list = vm_devices_list
($vmid);
3946 return 1 if defined($devices_list->{$deviceid});
3948 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3950 if ($deviceid eq 'tablet') {
3952 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3954 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3956 die "usb hotplug currently not reliable\n";
3957 # since we can't reliably hot unplug all added usb devices
3958 # and usb passthrough disables live migration
3959 # we disable usb hotplugging for now
3960 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3962 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3964 qemu_iothread_add
($vmid, $deviceid, $device);
3966 qemu_driveadd
($storecfg, $vmid, $device);
3967 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3969 qemu_deviceadd
($vmid, $devicefull);
3970 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3972 eval { qemu_drivedel
($vmid, $deviceid); };
3977 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3980 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3981 my $pciaddr = print_pci_addr
($deviceid);
3982 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3984 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3986 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3987 qemu_iothread_add
($vmid, $deviceid, $device);
3988 $devicefull .= ",iothread=iothread-$deviceid";
3991 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3992 $devicefull .= ",num_queues=$device->{queues}";
3995 qemu_deviceadd
($vmid, $devicefull);
3996 qemu_deviceaddverify
($vmid, $deviceid);
3998 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4000 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
4001 qemu_driveadd
($storecfg, $vmid, $device);
4003 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
4004 eval { qemu_deviceadd
($vmid, $devicefull); };
4006 eval { qemu_drivedel
($vmid, $deviceid); };
4011 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4013 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
4015 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4016 my $use_old_bios_files = undef;
4017 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4019 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
4020 qemu_deviceadd
($vmid, $netdevicefull);
4021 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4023 eval { qemu_netdevdel
($vmid, $deviceid); };
4028 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4031 my $pciaddr = print_pci_addr
($deviceid);
4032 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4034 qemu_deviceadd
($vmid, $devicefull);
4035 qemu_deviceaddverify
($vmid, $deviceid);
4038 die "can't hotplug device '$deviceid'\n";
4044 # fixme: this should raise exceptions on error!
4045 sub vm_deviceunplug
{
4046 my ($vmid, $conf, $deviceid) = @_;
4048 my $devices_list = vm_devices_list
($vmid);
4049 return 1 if !defined($devices_list->{$deviceid});
4051 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4053 if ($deviceid eq 'tablet') {
4055 qemu_devicedel
($vmid, $deviceid);
4057 } elsif ($deviceid =~ m/^usb\d+$/) {
4059 die "usb hotplug currently not reliable\n";
4060 # when unplugging usb devices this way,
4061 # there may be remaining usb controllers/hubs
4062 # so we disable it for now
4063 qemu_devicedel
($vmid, $deviceid);
4064 qemu_devicedelverify
($vmid, $deviceid);
4066 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4068 qemu_devicedel
($vmid, $deviceid);
4069 qemu_devicedelverify
($vmid, $deviceid);
4070 qemu_drivedel
($vmid, $deviceid);
4071 qemu_iothread_del
($conf, $vmid, $deviceid);
4073 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4075 qemu_devicedel
($vmid, $deviceid);
4076 qemu_devicedelverify
($vmid, $deviceid);
4077 qemu_iothread_del
($conf, $vmid, $deviceid);
4079 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4081 qemu_devicedel
($vmid, $deviceid);
4082 qemu_drivedel
($vmid, $deviceid);
4083 qemu_deletescsihw
($conf, $vmid, $deviceid);
4085 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4087 qemu_devicedel
($vmid, $deviceid);
4088 qemu_devicedelverify
($vmid, $deviceid);
4089 qemu_netdevdel
($vmid, $deviceid);
4092 die "can't unplug device '$deviceid'\n";
4098 sub qemu_deviceadd
{
4099 my ($vmid, $devicefull) = @_;
4101 $devicefull = "driver=".$devicefull;
4102 my %options = split(/[=,]/, $devicefull);
4104 vm_mon_cmd
($vmid, "device_add" , %options);
4107 sub qemu_devicedel
{
4108 my ($vmid, $deviceid) = @_;
4110 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4113 sub qemu_iothread_add
{
4114 my($vmid, $deviceid, $device) = @_;
4116 if ($device->{iothread
}) {
4117 my $iothreads = vm_iothreads_list
($vmid);
4118 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4122 sub qemu_iothread_del
{
4123 my($conf, $vmid, $deviceid) = @_;
4125 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4126 if ($device->{iothread
}) {
4127 my $iothreads = vm_iothreads_list
($vmid);
4128 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4132 sub qemu_objectadd
{
4133 my($vmid, $objectid, $qomtype) = @_;
4135 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4140 sub qemu_objectdel
{
4141 my($vmid, $objectid) = @_;
4143 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4149 my ($storecfg, $vmid, $device) = @_;
4151 my $drive = print_drive_full
($storecfg, $vmid, $device);
4152 $drive =~ s/\\/\\\\/g;
4153 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4155 # If the command succeeds qemu prints: "OK
"
4156 return 1 if $ret =~ m/OK/s;
4158 die "adding drive failed
: $ret\n";
4162 my($vmid, $deviceid) = @_;
4164 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4167 return 1 if $ret eq "";
4169 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4170 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4172 die "deleting drive
$deviceid failed
: $ret\n";
4175 sub qemu_deviceaddverify {
4176 my ($vmid, $deviceid) = @_;
4178 for (my $i = 0; $i <= 5; $i++) {
4179 my $devices_list = vm_devices_list($vmid);
4180 return 1 if defined($devices_list->{$deviceid});
4184 die "error on hotplug device
'$deviceid'\n";
4188 sub qemu_devicedelverify {
4189 my ($vmid, $deviceid) = @_;
4191 # need to verify that the device is correctly removed as device_del
4192 # is async and empty return is not reliable
4194 for (my $i = 0; $i <= 5; $i++) {
4195 my $devices_list = vm_devices_list($vmid);
4196 return 1 if !defined($devices_list->{$deviceid});
4200 die "error on hot-unplugging device
'$deviceid'\n";
4203 sub qemu_findorcreatescsihw {
4204 my ($storecfg, $conf, $vmid, $device) = @_;
4206 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4208 my $scsihwid="$controller_prefix$controller";
4209 my $devices_list = vm_devices_list($vmid);
4211 if(!defined($devices_list->{$scsihwid})) {
4212 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
4218 sub qemu_deletescsihw {
4219 my ($conf, $vmid, $opt) = @_;
4221 my $device = parse_drive($opt, $conf->{$opt});
4223 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4224 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4228 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4230 my $devices_list = vm_devices_list($vmid);
4231 foreach my $opt (keys %{$devices_list}) {
4232 if (PVE::QemuServer::is_valid_drivename($opt)) {
4233 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4234 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4240 my $scsihwid="scsihw
$controller";
4242 vm_deviceunplug($vmid, $conf, $scsihwid);
4247 sub qemu_add_pci_bridge {
4248 my ($storecfg, $conf, $vmid, $device) = @_;
4254 print_pci_addr($device, $bridges);
4256 while (my ($k, $v) = each %$bridges) {
4259 return 1 if !defined($bridgeid) || $bridgeid < 1;
4261 my $bridge = "pci
.$bridgeid";
4262 my $devices_list = vm_devices_list($vmid);
4264 if (!defined($devices_list->{$bridge})) {
4265 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
4271 sub qemu_set_link_status {
4272 my ($vmid, $device, $up) = @_;
4274 vm_mon_cmd($vmid, "set_link
", name => $device,
4275 up => $up ? JSON::true : JSON::false);
4278 sub qemu_netdevadd {
4279 my ($vmid, $conf, $device, $deviceid) = @_;
4281 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
4282 my %options = split(/[=,]/, $netdev);
4284 vm_mon_cmd($vmid, "netdev_add
", %options);
4288 sub qemu_netdevdel {
4289 my ($vmid, $deviceid) = @_;
4291 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4294 sub qemu_usb_hotplug {
4295 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4299 # remove the old one first
4300 vm_deviceunplug($vmid, $conf, $deviceid);
4302 # check if xhci controller is necessary and available
4303 if ($device->{usb3}) {
4305 my $devicelist = vm_devices_list($vmid);
4307 if (!$devicelist->{xhci}) {
4308 my $pciaddr = print_pci_addr("xhci
");
4309 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4312 my $d = parse_usb_device($device->{host});
4313 $d->{usb3} = $device->{usb3};
4316 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4319 sub qemu_cpu_hotplug {
4320 my ($vmid, $conf, $vcpus) = @_;
4322 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4325 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4326 $sockets = $conf->{sockets} if $conf->{sockets};
4327 my $cores = $conf->{cores} || 1;
4328 my $maxcpus = $sockets * $cores;
4330 $vcpus = $maxcpus if !$vcpus;
4332 die "you can
't add more vcpus than maxcpus\n"
4333 if $vcpus > $maxcpus;
4335 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4337 if ($vcpus < $currentvcpus) {
4339 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4341 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4342 qemu_devicedel($vmid, "cpu$i");
4344 my $currentrunningvcpus = undef;
4346 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4347 last if scalar(@{$currentrunningvcpus}) == $i-1;
4348 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4352 #update conf after each succesfull cpu unplug
4353 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4354 PVE::QemuConfig->write_config($vmid, $conf);
4357 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4363 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4364 die "vcpus in running vm does not match its configuration\n"
4365 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4367 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4369 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4370 my $cpustr = print_cpu_device($conf, $i);
4371 qemu_deviceadd($vmid, $cpustr);
4374 my $currentrunningvcpus = undef;
4376 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4377 last if scalar(@{$currentrunningvcpus}) == $i;
4378 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4382 #update conf after each succesfull cpu hotplug
4383 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4384 PVE::QemuConfig->write_config($vmid, $conf);
4388 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4389 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4394 sub qemu_block_set_io_throttle {
4395 my ($vmid, $deviceid,
4396 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4397 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4398 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4399 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4401 return if !check_running($vmid) ;
4403 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4405 bps_rd => int($bps_rd),
4406 bps_wr => int($bps_wr),
4408 iops_rd => int($iops_rd),
4409 iops_wr => int($iops_wr),
4410 bps_max => int($bps_max),
4411 bps_rd_max => int($bps_rd_max),
4412 bps_wr_max => int($bps_wr_max),
4413 iops_max => int($iops_max),
4414 iops_rd_max => int($iops_rd_max),
4415 iops_wr_max => int($iops_wr_max),
4416 bps_max_length => int($bps_max_length),
4417 bps_rd_max_length => int($bps_rd_max_length),
4418 bps_wr_max_length => int($bps_wr_max_length),
4419 iops_max_length => int($iops_max_length),
4420 iops_rd_max_length => int($iops_rd_max_length),
4421 iops_wr_max_length => int($iops_wr_max_length),
4426 # old code, only used to shutdown old VM after update
4428 my ($fh, $timeout) = @_;
4430 my $sel = new IO::Select;
4437 while (scalar (@ready = $sel->can_read($timeout))) {
4439 if ($count = $fh->sysread($buf, 8192)) {
4440 if ($buf =~ /^(.*)\(qemu\) $/s) {
4447 if (!defined($count)) {
4454 die "monitor read timeout\n" if !scalar(@ready);
4459 sub qemu_block_resize {
4460 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4462 my $running = check_running($vmid);
4464 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4466 return if !$running;
4468 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4472 sub qemu_volume_snapshot {
4473 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4475 my $running = check_running($vmid);
4477 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4478 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4480 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4484 sub qemu_volume_snapshot_delete {
4485 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4487 my $running = check_running($vmid);
4492 my $conf = PVE::QemuConfig->load_config($vmid);
4493 foreach_drive($conf, sub {
4494 my ($ds, $drive) = @_;
4495 $running = 1 if $drive->{file} eq $volid;
4499 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4500 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4502 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4506 sub set_migration_caps {
4512 "auto-converge" => 1,
4514 "x-rdma-pin-all" => 0,
4519 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4521 for my $supported_capability (@$supported_capabilities) {
4523 capability => $supported_capability->{capability},
4524 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4528 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4531 my $fast_plug_option = {
4539 'vmstatestorage
' => 1,
4542 # hotplug changes in [PENDING]
4543 # $selection hash can be used to only apply specified options, for
4544 # example: { cores => 1 } (only apply changed 'cores
')
4545 # $errors ref is used to return error messages
4546 sub vmconfig_hotplug_pending {
4547 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4549 my $defaults = load_defaults();
4551 # commit values which do not have any impact on running VM first
4552 # Note: those option cannot raise errors, we we do not care about
4553 # $selection and always apply them.
4555 my $add_error = sub {
4556 my ($opt, $msg) = @_;
4557 $errors->{$opt} = "hotplug problem - $msg";
4561 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4562 if ($fast_plug_option->{$opt}) {
4563 $conf->{$opt} = $conf->{pending}->{$opt};
4564 delete $conf->{pending}->{$opt};
4570 PVE::QemuConfig->write_config($vmid, $conf);
4571 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4574 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4576 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4577 while (my ($opt, $force) = each %$pending_delete_hash) {
4578 next if $selection && !$selection->{$opt};
4580 if ($opt eq 'hotplug
') {
4581 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4582 } elsif ($opt eq 'tablet
') {
4583 die "skip\n" if !$hotplug_features->{usb};
4584 if ($defaults->{tablet}) {
4585 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4587 vm_deviceunplug($vmid, $conf, $opt);
4589 } elsif ($opt =~ m/^usb\d+/) {
4591 # since we cannot reliably hot unplug usb devices
4592 # we are disabling it
4593 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4594 vm_deviceunplug($vmid, $conf, $opt);
4595 } elsif ($opt eq 'vcpus
') {
4596 die "skip\n" if !$hotplug_features->{cpu};
4597 qemu_cpu_hotplug($vmid, $conf, undef);
4598 } elsif ($opt eq 'balloon
') {
4599 # enable balloon device is not hotpluggable
4600 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4601 # here we reset the ballooning value to memory
4602 my $balloon = $conf->{memory} || $defaults->{memory};
4603 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4604 } elsif ($fast_plug_option->{$opt}) {
4606 } elsif ($opt =~ m/^net(\d+)$/) {
4607 die "skip\n" if !$hotplug_features->{network};
4608 vm_deviceunplug($vmid, $conf, $opt);
4609 } elsif (is_valid_drivename($opt)) {
4610 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4611 vm_deviceunplug($vmid, $conf, $opt);
4612 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4613 } elsif ($opt =~ m/^memory$/) {
4614 die "skip\n" if !$hotplug_features->{memory};
4615 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4616 } elsif ($opt eq 'cpuunits
') {
4617 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4618 } elsif ($opt eq 'cpulimit
') {
4619 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4625 &$add_error($opt, $err) if $err ne "skip\n";
4627 # save new config if hotplug was successful
4628 delete $conf->{$opt};
4629 vmconfig_undelete_pending_option($conf, $opt);
4630 PVE::QemuConfig->write_config($vmid, $conf);
4631 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4635 my $apply_pending_cloudinit;
4636 $apply_pending_cloudinit = sub {
4637 my ($key, $value) = @_;
4638 $apply_pending_cloudinit = sub {}; # once is enough
4640 my @cloudinit_opts = keys %$confdesc_cloudinit;
4641 foreach my $opt (keys %{$conf->{pending}}) {
4642 next if !grep { $_ eq $opt } @cloudinit_opts;
4643 $conf->{$opt} = delete $conf->{pending}->{$opt};
4646 my $new_conf = { %$conf };
4647 $new_conf->{$key} = $value;
4648 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4651 foreach my $opt (keys %{$conf->{pending}}) {
4652 next if $selection && !$selection->{$opt};
4653 my $value = $conf->{pending}->{$opt};
4655 if ($opt eq 'hotplug
') {
4656 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4657 } elsif ($opt eq 'tablet
') {
4658 die "skip\n" if !$hotplug_features->{usb};
4660 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4661 } elsif ($value == 0) {
4662 vm_deviceunplug($vmid, $conf, $opt);
4664 } elsif ($opt =~ m/^usb\d+$/) {
4666 # since we cannot reliably hot unplug usb devices
4667 # we are disabling it
4668 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4669 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4670 die "skip\n" if !$d;
4671 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4672 } elsif ($opt eq 'vcpus
') {
4673 die "skip\n" if !$hotplug_features->{cpu};
4674 qemu_cpu_hotplug($vmid, $conf, $value);
4675 } elsif ($opt eq 'balloon
') {
4676 # enable/disable balloning device is not hotpluggable
4677 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4678 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4679 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4681 # allow manual ballooning if shares is set to zero
4682 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4683 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4684 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4686 } elsif ($opt =~ m/^net(\d+)$/) {
4687 # some changes can be done without hotplug
4688 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4689 $vmid, $opt, $value);
4690 } elsif (is_valid_drivename($opt)) {
4691 # some changes can be done without hotplug
4692 my $drive = parse_drive($opt, $value);
4693 if (drive_is_cloudinit($drive)) {
4694 &$apply_pending_cloudinit($opt, $value);
4696 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4697 $vmid, $opt, $value, 1);
4698 } elsif ($opt =~ m/^memory$/) { #dimms
4699 die "skip\n" if !$hotplug_features->{memory};
4700 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4701 } elsif ($opt eq 'cpuunits
') {
4702 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4703 } elsif ($opt eq 'cpulimit
') {
4704 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4705 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4707 die "skip\n"; # skip non-hot-pluggable options
4711 &$add_error($opt, $err) if $err ne "skip\n";
4713 # save new config if hotplug was successful
4714 $conf->{$opt} = $value;
4715 delete $conf->{pending}->{$opt};
4716 PVE::QemuConfig->write_config($vmid, $conf);
4717 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4722 sub try_deallocate_drive {
4723 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4725 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4726 my $volid = $drive->{file};
4727 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4728 my $sid = PVE::Storage::parse_volume_id($volid);
4729 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4731 # check if the disk is really unused
4732 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4733 if is_volume_in_use($storecfg, $conf, $key, $volid);
4734 PVE::Storage::vdisk_free($storecfg, $volid);
4737 # If vm is not owner of this disk remove from config
4745 sub vmconfig_delete_or_detach_drive {
4746 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4748 my $drive = parse_drive($opt, $conf->{$opt});
4750 my $rpcenv = PVE::RPCEnvironment::get();
4751 my $authuser = $rpcenv->get_user();
4754 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4755 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4757 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4761 sub vmconfig_apply_pending {
4762 my ($vmid, $conf, $storecfg) = @_;
4766 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4767 while (my ($opt, $force) = each %$pending_delete_hash) {
4768 die "internal error" if $opt =~ m/^unused/;
4769 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4770 if (!defined($conf->{$opt})) {
4771 vmconfig_undelete_pending_option($conf, $opt);
4772 PVE::QemuConfig->write_config($vmid, $conf);
4773 } elsif (is_valid_drivename($opt)) {
4774 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4775 vmconfig_undelete_pending_option($conf, $opt);
4776 delete $conf->{$opt};
4777 PVE::QemuConfig->write_config($vmid, $conf);
4779 vmconfig_undelete_pending_option($conf, $opt);
4780 delete $conf->{$opt};
4781 PVE::QemuConfig->write_config($vmid, $conf);
4785 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4787 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4788 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4790 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4791 # skip if nothing changed
4792 } elsif (is_valid_drivename($opt)) {
4793 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4794 if defined($conf->{$opt});
4795 $conf->{$opt} = $conf->{pending}->{$opt};
4797 $conf->{$opt} = $conf->{pending}->{$opt};
4800 delete $conf->{pending}->{$opt};
4801 PVE::QemuConfig->write_config($vmid, $conf);
4805 my $safe_num_ne = sub {
4808 return 0 if !defined($a) && !defined($b);
4809 return 1 if !defined($a);
4810 return 1 if !defined($b);
4815 my $safe_string_ne = sub {
4818 return 0 if !defined($a) && !defined($b);
4819 return 1 if !defined($a);
4820 return 1 if !defined($b);
4825 sub vmconfig_update_net {
4826 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4828 my $newnet = parse_net($value);
4830 if ($conf->{$opt}) {
4831 my $oldnet = parse_net($conf->{$opt});
4833 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4834 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4835 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4836 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4838 # for non online change, we try to hot-unplug
4839 die "skip\n" if !$hotplug;
4840 vm_deviceunplug($vmid, $conf, $opt);
4843 die "internal error" if $opt !~ m/net(\d+)/;
4844 my $iface = "tap${vmid}i$1";
4846 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4847 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4848 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4849 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4850 PVE::Network::tap_unplug($iface);
4851 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4852 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4853 # Rate can be applied on its own but any change above needs to
4854 # include the rate in tap_plug since OVS resets everything.
4855 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4858 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4859 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4867 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4873 sub vmconfig_update_disk {
4874 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4876 # fixme: do we need force?
4878 my $drive = parse_drive($opt, $value);
4880 if ($conf->{$opt}) {
4882 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4884 my $media = $drive->{media} || 'disk
';
4885 my $oldmedia = $old_drive->{media} || 'disk
';
4886 die "unable to change media type\n" if $media ne $oldmedia;
4888 if (!drive_is_cdrom($old_drive)) {
4890 if ($drive->{file} ne $old_drive->{file}) {
4892 die "skip\n" if !$hotplug;
4894 # unplug and register as unused
4895 vm_deviceunplug($vmid, $conf, $opt);
4896 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4899 # update existing disk
4901 # skip non hotpluggable value
4902 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4903 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4904 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4905 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4910 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4911 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4912 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4913 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4914 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4915 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4916 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4917 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4918 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4919 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4920 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4921 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4922 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4923 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4924 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4925 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4926 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4927 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4929 qemu_block_set_io_throttle($vmid,"drive-$opt",
4930 ($drive->{mbps} || 0)*1024*1024,
4931 ($drive->{mbps_rd} || 0)*1024*1024,
4932 ($drive->{mbps_wr} || 0)*1024*1024,
4933 $drive->{iops} || 0,
4934 $drive->{iops_rd} || 0,
4935 $drive->{iops_wr} || 0,
4936 ($drive->{mbps_max} || 0)*1024*1024,
4937 ($drive->{mbps_rd_max} || 0)*1024*1024,
4938 ($drive->{mbps_wr_max} || 0)*1024*1024,
4939 $drive->{iops_max} || 0,
4940 $drive->{iops_rd_max} || 0,
4941 $drive->{iops_wr_max} || 0,
4942 $drive->{bps_max_length} || 1,
4943 $drive->{bps_rd_max_length} || 1,
4944 $drive->{bps_wr_max_length} || 1,
4945 $drive->{iops_max_length} || 1,
4946 $drive->{iops_rd_max_length} || 1,
4947 $drive->{iops_wr_max_length} || 1);
4956 if ($drive->{file} eq 'none
') {
4957 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4958 if (drive_is_cloudinit($old_drive)) {
4959 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4962 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4963 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4964 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4972 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4974 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4975 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4979 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4980 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4982 PVE::QemuConfig->lock_config($vmid, sub {
4983 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4985 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4987 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4989 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4991 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4992 vmconfig_apply_pending($vmid, $conf, $storecfg);
4993 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4996 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4998 my $defaults = load_defaults();
5000 # set environment variable useful inside network script
5001 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5003 my $local_volumes = {};
5005 if ($targetstorage) {
5006 foreach_drive($conf, sub {
5007 my ($ds, $drive) = @_;
5009 return if drive_is_cdrom($drive);
5011 my $volid = $drive->{file};
5015 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5017 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5018 return if $scfg->{shared};
5019 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5024 foreach my $opt (sort keys %$local_volumes) {
5026 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5027 my $drive = parse_drive($opt, $conf->{$opt});
5029 #if remote storage is specified, use default format
5030 if ($targetstorage && $targetstorage ne "1") {
5031 $storeid = $targetstorage;
5032 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5033 $format = $defFormat;
5035 #else we use same format than original
5036 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5037 $format = qemu_img_format($scfg, $volid);
5040 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5041 my $newdrive = $drive;
5042 $newdrive->{format} = $format;
5043 $newdrive->{file} = $newvolid;
5044 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5045 $local_volumes->{$opt} = $drivestr;
5046 #pass drive to conf for command line
5047 $conf->{$opt} = $drivestr;
5051 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5053 my $migrate_port = 0;
5056 if ($statefile eq 'tcp
') {
5057 my $localip = "localhost";
5058 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5059 my $nodename = PVE::INotify::nodename();
5061 if (!defined($migration_type)) {
5062 if (defined($datacenterconf->{migration}->{type})) {
5063 $migration_type = $datacenterconf->{migration}->{type};
5065 $migration_type = 'secure
';
5069 if ($migration_type eq 'insecure
') {
5070 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5071 if ($migrate_network_addr) {
5072 $localip = $migrate_network_addr;
5074 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5077 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5080 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5081 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5082 $migrate_uri = "tcp:${localip}:${migrate_port}";
5083 push @$cmd, '-incoming
', $migrate_uri;
5086 } elsif ($statefile eq 'unix
') {
5087 # should be default for secure migrations as a ssh TCP forward
5088 # tunnel is not deterministic reliable ready and fails regurarly
5089 # to set up in time, so use UNIX socket forwards
5090 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5091 unlink $socket_addr;
5093 $migrate_uri = "unix:$socket_addr";
5095 push @$cmd, '-incoming
', $migrate_uri;
5099 push @$cmd, '-loadstate
', $statefile;
5106 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5107 my $d = parse_hostpci($conf->{"hostpci$i"});
5109 my $pcidevices = $d->{pciid};
5110 foreach my $pcidevice (@$pcidevices) {
5111 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
5113 my $info = pci_device_info("0000:$pciid");
5114 die "IOMMU not present\n" if !check_iommu_support();
5115 die "no pci device info for device '$pciid'\n" if !$info;
5116 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
5117 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
5121 PVE::Storage::activate_volumes($storecfg, $vollist);
5123 if (!check_running($vmid, 1)) {
5125 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5126 outfunc => sub {}, errfunc => sub {});
5130 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5131 : $defaults->{cpuunits};
5133 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5134 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5137 Slice => 'qemu
.slice
',
5139 CPUShares => $cpuunits
5142 if (my $cpulimit = $conf->{cpulimit}) {
5143 $properties{CPUQuota} = int($cpulimit * 100);
5145 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5147 my $run_qemu = sub {
5148 PVE::Tools::run_fork sub {
5149 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5150 run_command($cmd, %run_params);
5154 if ($conf->{hugepages}) {
5157 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5158 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5160 PVE::QemuServer::Memory::hugepages_mount();
5161 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5163 eval { $run_qemu->() };
5165 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5169 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5171 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5174 eval { $run_qemu->() };
5178 # deactivate volumes if start fails
5179 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5180 die "start failed: $err";
5183 print "migration listens on $migrate_uri\n" if $migrate_uri;
5185 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5186 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5190 #start nbd server for storage migration
5191 if ($targetstorage) {
5192 my $nodename = PVE::INotify::nodename();
5193 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5194 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5195 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5196 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5198 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5200 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5202 foreach my $opt (sort keys %$local_volumes) {
5203 my $volid = $local_volumes->{$opt};
5204 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5205 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5206 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5210 if ($migratedfrom) {
5212 set_migration_caps($vmid);
5217 print "spice listens on port $spice_port\n";
5218 if ($spice_ticket) {
5219 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5220 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5225 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5226 if !$statefile && $conf->{balloon};
5228 foreach my $opt (keys %$conf) {
5229 next if $opt !~ m/^net\d+$/;
5230 my $nicconf = parse_net($conf->{$opt});
5231 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5235 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5236 path => "machine/peripheral/balloon0",
5237 property => "guest-stats-polling-interval",
5238 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5244 my ($vmid, $execute, %params) = @_;
5246 my $cmd = { execute => $execute, arguments => \%params };
5247 vm_qmp_command($vmid, $cmd);
5250 sub vm_mon_cmd_nocheck {
5251 my ($vmid, $execute, %params) = @_;
5253 my $cmd = { execute => $execute, arguments => \%params };
5254 vm_qmp_command($vmid, $cmd, 1);
5257 sub vm_qmp_command {
5258 my ($vmid, $cmd, $nocheck) = @_;
5263 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5264 $timeout = $cmd->{arguments}->{timeout};
5265 delete $cmd->{arguments}->{timeout};
5269 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5270 my $sname = qmp_socket($vmid);
5271 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5272 my $qmpclient = PVE::QMPClient->new();
5274 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5276 die "unable to open monitor socket\n";
5280 syslog("err", "VM $vmid qmp command failed - $err");
5287 sub vm_human_monitor_command {
5288 my ($vmid, $cmdline) = @_;
5293 execute => 'human-monitor-command
',
5294 arguments => { 'command-line
' => $cmdline},
5297 return vm_qmp_command($vmid, $cmd);
5300 sub vm_commandline {
5301 my ($storecfg, $vmid) = @_;
5303 my $conf = PVE::QemuConfig->load_config($vmid);
5305 my $defaults = load_defaults();
5307 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5309 return PVE::Tools::cmd2string($cmd);
5313 my ($vmid, $skiplock) = @_;
5315 PVE::QemuConfig->lock_config($vmid, sub {
5317 my $conf = PVE::QemuConfig->load_config($vmid);
5319 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5321 vm_mon_cmd($vmid, "system_reset");
5325 sub get_vm_volumes {
5329 foreach_volid($conf, sub {
5330 my ($volid, $attr) = @_;
5332 return if $volid =~ m|^/|;
5334 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5337 push @$vollist, $volid;
5343 sub vm_stop_cleanup {
5344 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5349 my $vollist = get_vm_volumes($conf);
5350 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5353 foreach my $ext (qw(mon qmp pid vnc qga)) {
5354 unlink "/var/run/qemu-server/${vmid}.$ext";
5357 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5359 warn $@ if $@; # avoid errors - just warn
5362 # Note: use $nockeck to skip tests if VM configuration file exists.
5363 # We need that when migration VMs to other nodes (files already moved)
5364 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5366 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5368 $force = 1 if !defined($force) && !$shutdown;
5371 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5372 kill 15, $pid if $pid;
5373 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5374 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5378 PVE
::QemuConfig-
>lock_config($vmid, sub {
5380 my $pid = check_running
($vmid, $nocheck);
5385 $conf = PVE
::QemuConfig-
>load_config($vmid);
5386 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5387 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5388 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5389 $timeout = $opts->{down
} if $opts->{down
};
5393 $timeout = 60 if !defined($timeout);
5397 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5398 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5400 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5403 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5410 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5415 if ($count >= $timeout) {
5417 warn "VM still running - terminating now with SIGTERM\n";
5420 die "VM quit/powerdown failed - got timeout\n";
5423 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5428 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5431 die "VM quit/powerdown failed\n";
5439 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5444 if ($count >= $timeout) {
5445 warn "VM still running - terminating now with SIGKILL\n";
5450 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5455 my ($vmid, $skiplock) = @_;
5457 PVE
::QemuConfig-
>lock_config($vmid, sub {
5459 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5461 PVE
::QemuConfig-
>check_lock($conf)
5462 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5464 vm_mon_cmd
($vmid, "stop");
5469 my ($vmid, $skiplock, $nocheck) = @_;
5471 PVE
::QemuConfig-
>lock_config($vmid, sub {
5473 my $res = vm_mon_cmd
($vmid, 'query-status');
5474 my $resume_cmd = 'cont';
5476 if ($res->{status
} && $res->{status
} eq 'suspended') {
5477 $resume_cmd = 'system_wakeup';
5482 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5484 PVE
::QemuConfig-
>check_lock($conf)
5485 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5487 vm_mon_cmd
($vmid, $resume_cmd);
5490 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5496 my ($vmid, $skiplock, $key) = @_;
5498 PVE
::QemuConfig-
>lock_config($vmid, sub {
5500 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5502 # there is no qmp command, so we use the human monitor command
5503 vm_human_monitor_command
($vmid, "sendkey $key");
5508 my ($storecfg, $vmid, $skiplock) = @_;
5510 PVE
::QemuConfig-
>lock_config($vmid, sub {
5512 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5514 if (!check_running
($vmid)) {
5515 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5517 die "VM $vmid is running - destroy failed\n";
5525 my ($filename, $buf) = @_;
5527 my $fh = IO
::File-
>new($filename, "w");
5528 return undef if !$fh;
5530 my $res = print $fh $buf;
5537 sub pci_device_info
{
5542 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5543 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5545 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5546 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5548 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5549 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5551 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5552 return undef if !defined($product) || $product !~ s/^0x//;
5557 product
=> $product,
5563 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5572 my $name = $dev->{name
};
5574 my $fn = "$pcisysfs/devices/$name/reset";
5576 return file_write
($fn, "1");
5579 sub pci_dev_bind_to_vfio
{
5582 my $name = $dev->{name
};
5584 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5586 if (!-d
$vfio_basedir) {
5587 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5589 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5591 my $testdir = "$vfio_basedir/$name";
5592 return 1 if -d
$testdir;
5594 my $data = "$dev->{vendor} $dev->{product}";
5595 return undef if !file_write
("$vfio_basedir/new_id", $data);
5597 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5598 if (!file_write
($fn, $name)) {
5599 return undef if -f
$fn;
5602 $fn = "$vfio_basedir/bind";
5603 if (! -d
$testdir) {
5604 return undef if !file_write
($fn, $name);
5610 sub pci_dev_group_bind_to_vfio
{
5613 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5615 if (!-d
$vfio_basedir) {
5616 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5618 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5620 # get IOMMU group devices
5621 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5622 my @devs = grep /^0000:/, readdir($D);
5625 foreach my $pciid (@devs) {
5626 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5628 # pci bridges, switches or root ports are not supported
5629 # they have a pci_bus subdirectory so skip them
5630 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5632 my $info = pci_device_info
($1);
5633 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5639 # vzdump restore implementaion
5641 sub tar_archive_read_firstfile
{
5642 my $archive = shift;
5644 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5646 # try to detect archive type first
5647 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5648 die "unable to open file '$archive'\n";
5649 my $firstfile = <$fh>;
5653 die "ERROR: archive contaions no data\n" if !$firstfile;
5659 sub tar_restore_cleanup
{
5660 my ($storecfg, $statfile) = @_;
5662 print STDERR
"starting cleanup\n";
5664 if (my $fd = IO
::File-
>new($statfile, "r")) {
5665 while (defined(my $line = <$fd>)) {
5666 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5669 if ($volid =~ m
|^/|) {
5670 unlink $volid || die 'unlink failed\n';
5672 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5674 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5676 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5678 print STDERR
"unable to parse line in statfile - $line";
5685 sub restore_archive
{
5686 my ($archive, $vmid, $user, $opts) = @_;
5688 my $format = $opts->{format
};
5691 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5692 $format = 'tar' if !$format;
5694 } elsif ($archive =~ m/\.tar$/) {
5695 $format = 'tar' if !$format;
5696 } elsif ($archive =~ m/.tar.lzo$/) {
5697 $format = 'tar' if !$format;
5699 } elsif ($archive =~ m/\.vma$/) {
5700 $format = 'vma' if !$format;
5701 } elsif ($archive =~ m/\.vma\.gz$/) {
5702 $format = 'vma' if !$format;
5704 } elsif ($archive =~ m/\.vma\.lzo$/) {
5705 $format = 'vma' if !$format;
5708 $format = 'vma' if !$format; # default
5711 # try to detect archive format
5712 if ($format eq 'tar') {
5713 return restore_tar_archive
($archive, $vmid, $user, $opts);
5715 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5719 sub restore_update_config_line
{
5720 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5722 return if $line =~ m/^\#qmdump\#/;
5723 return if $line =~ m/^\#vzdump\#/;
5724 return if $line =~ m/^lock:/;
5725 return if $line =~ m/^unused\d+:/;
5726 return if $line =~ m/^parent:/;
5727 return if $line =~ m/^template:/; # restored VM is never a template
5729 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5730 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5731 # try to convert old 1.X settings
5732 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5733 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5734 my ($model, $macaddr) = split(/\=/, $devconfig);
5735 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5738 bridge
=> "vmbr$ind",
5739 macaddr
=> $macaddr,
5741 my $netstr = print_net
($net);
5743 print $outfd "net$cookie->{netcount}: $netstr\n";
5744 $cookie->{netcount
}++;
5746 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5747 my ($id, $netstr) = ($1, $2);
5748 my $net = parse_net
($netstr);
5749 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5750 $netstr = print_net
($net);
5751 print $outfd "$id: $netstr\n";
5752 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5755 my $di = parse_drive
($virtdev, $value);
5756 if (defined($di->{backup
}) && !$di->{backup
}) {
5757 print $outfd "#$line";
5758 } elsif ($map->{$virtdev}) {
5759 delete $di->{format
}; # format can change on restore
5760 $di->{file
} = $map->{$virtdev};
5761 $value = print_drive
($vmid, $di);
5762 print $outfd "$virtdev: $value\n";
5766 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5768 if ($vmgenid ne '0') {
5769 # always generate a new vmgenid if there was a valid one setup
5770 $vmgenid = generate_uuid
();
5772 print $outfd "vmgenid: $vmgenid\n";
5773 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5774 my ($uuid, $uuid_str);
5775 UUID
::generate
($uuid);
5776 UUID
::unparse
($uuid, $uuid_str);
5777 my $smbios1 = parse_smbios1
($2);
5778 $smbios1->{uuid
} = $uuid_str;
5779 print $outfd $1.print_smbios1
($smbios1)."\n";
5786 my ($cfg, $vmid) = @_;
5788 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5790 my $volid_hash = {};
5791 foreach my $storeid (keys %$info) {
5792 foreach my $item (@{$info->{$storeid}}) {
5793 next if !($item->{volid
} && $item->{size
});
5794 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5795 $volid_hash->{$item->{volid
}} = $item;
5802 sub is_volume_in_use
{
5803 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5805 my $path = PVE
::Storage
::path
($storecfg, $volid);
5807 my $scan_config = sub {
5808 my ($cref, $snapname) = @_;
5810 foreach my $key (keys %$cref) {
5811 my $value = $cref->{$key};
5812 if (is_valid_drivename
($key)) {
5813 next if $skip_drive && $key eq $skip_drive;
5814 my $drive = parse_drive
($key, $value);
5815 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5816 return 1 if $volid eq $drive->{file
};
5817 if ($drive->{file
} =~ m!^/!) {
5818 return 1 if $drive->{file
} eq $path;
5820 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5822 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5824 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5832 return 1 if &$scan_config($conf);
5836 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5837 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5843 sub update_disksize
{
5844 my ($vmid, $conf, $volid_hash) = @_;
5847 my $prefix = "VM $vmid:";
5849 # used and unused disks
5850 my $referenced = {};
5852 # Note: it is allowed to define multiple storages with same path (alias), so
5853 # we need to check both 'volid' and real 'path' (two different volid can point
5854 # to the same path).
5856 my $referencedpath = {};
5859 foreach my $opt (keys %$conf) {
5860 if (is_valid_drivename
($opt)) {
5861 my $drive = parse_drive
($opt, $conf->{$opt});
5862 my $volid = $drive->{file
};
5865 $referenced->{$volid} = 1;
5866 if ($volid_hash->{$volid} &&
5867 (my $path = $volid_hash->{$volid}->{path
})) {
5868 $referencedpath->{$path} = 1;
5871 next if drive_is_cdrom
($drive);
5872 next if !$volid_hash->{$volid};
5874 $drive->{size
} = $volid_hash->{$volid}->{size
};
5875 my $new = print_drive
($vmid, $drive);
5876 if ($new ne $conf->{$opt}) {
5878 $conf->{$opt} = $new;
5879 print "$prefix update disk '$opt' information.\n";
5884 # remove 'unusedX' entry if volume is used
5885 foreach my $opt (keys %$conf) {
5886 next if $opt !~ m/^unused\d+$/;
5887 my $volid = $conf->{$opt};
5888 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5889 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5890 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5892 delete $conf->{$opt};
5895 $referenced->{$volid} = 1;
5896 $referencedpath->{$path} = 1 if $path;
5899 foreach my $volid (sort keys %$volid_hash) {
5900 next if $volid =~ m/vm-$vmid-state-/;
5901 next if $referenced->{$volid};
5902 my $path = $volid_hash->{$volid}->{path
};
5903 next if !$path; # just to be sure
5904 next if $referencedpath->{$path};
5906 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5907 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5908 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5915 my ($vmid, $nolock, $dryrun) = @_;
5917 my $cfg = PVE
::Storage
::config
();
5919 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5920 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5921 foreach my $stor (keys %{$cfg->{ids
}}) {
5922 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5925 print "rescan volumes...\n";
5926 my $volid_hash = scan_volids
($cfg, $vmid);
5928 my $updatefn = sub {
5931 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5933 PVE
::QemuConfig-
>check_lock($conf);
5936 foreach my $volid (keys %$volid_hash) {
5937 my $info = $volid_hash->{$volid};
5938 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5941 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5943 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5946 if (defined($vmid)) {
5950 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5953 my $vmlist = config_list
();
5954 foreach my $vmid (keys %$vmlist) {
5958 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5964 sub restore_vma_archive
{
5965 my ($archive, $vmid, $user, $opts, $comp) = @_;
5967 my $readfrom = $archive;
5969 my $cfg = PVE
::Storage
::config
();
5971 my $bwlimit = $opts->{bwlimit
};
5973 my $dbg_cmdstring = '';
5974 my $add_pipe = sub {
5976 push @$commands, $cmd;
5977 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5978 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5983 if ($archive eq '-') {
5986 # If we use a backup from a PVE defined storage we also consider that
5987 # storage's rate limit:
5988 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5989 if (defined($volid)) {
5990 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5991 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5993 print STDERR
"applying read rate limit: $readlimit\n";
5994 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5995 $add_pipe->($cstream);
6002 if ($comp eq 'gzip') {
6003 $cmd = ['zcat', $readfrom];
6004 } elsif ($comp eq 'lzop') {
6005 $cmd = ['lzop', '-d', '-c', $readfrom];
6007 die "unknown compression method '$comp'\n";
6012 my $tmpdir = "/var/tmp/vzdumptmp$$";
6015 # disable interrupts (always do cleanups)
6019 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6021 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6022 POSIX
::mkfifo
($mapfifo, 0600);
6025 my $openfifo = sub {
6026 open($fifofh, '>', $mapfifo) || die $!;
6029 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6036 my $rpcenv = PVE
::RPCEnvironment
::get
();
6038 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6039 my $tmpfn = "$conffile.$$.tmp";
6041 # Note: $oldconf is undef if VM does not exists
6042 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6043 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6047 my $print_devmap = sub {
6048 my $virtdev_hash = {};
6050 my $cfgfn = "$tmpdir/qemu-server.conf";
6052 # we can read the config - that is already extracted
6053 my $fh = IO
::File-
>new($cfgfn, "r") ||
6054 "unable to read qemu-server.conf - $!\n";
6056 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6058 my $pve_firewall_dir = '/etc/pve/firewall';
6059 mkdir $pve_firewall_dir; # make sure the dir exists
6060 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6063 while (defined(my $line = <$fh>)) {
6064 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6065 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6066 die "archive does not contain data for drive '$virtdev'\n"
6067 if !$devinfo->{$devname};
6068 if (defined($opts->{storage
})) {
6069 $storeid = $opts->{storage
} || 'local';
6070 } elsif (!$storeid) {
6073 $format = 'raw' if !$format;
6074 $devinfo->{$devname}->{devname
} = $devname;
6075 $devinfo->{$devname}->{virtdev
} = $virtdev;
6076 $devinfo->{$devname}->{format
} = $format;
6077 $devinfo->{$devname}->{storeid
} = $storeid;
6079 # check permission on storage
6080 my $pool = $opts->{pool
}; # todo: do we need that?
6081 if ($user ne 'root@pam') {
6082 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6085 $storage_limits{$storeid} = $bwlimit;
6087 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6091 foreach my $key (keys %storage_limits) {
6092 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6094 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6095 $storage_limits{$key} = $limit * 1024;
6098 foreach my $devname (keys %$devinfo) {
6099 die "found no device mapping information for device '$devname'\n"
6100 if !$devinfo->{$devname}->{virtdev
};
6103 # create empty/temp config
6105 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6106 foreach_drive
($oldconf, sub {
6107 my ($ds, $drive) = @_;
6109 return if drive_is_cdrom
($drive);
6111 my $volid = $drive->{file
};
6113 return if !$volid || $volid =~ m
|^/|;
6115 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6116 return if !$path || !$owner || ($owner != $vmid);
6118 # Note: only delete disk we want to restore
6119 # other volumes will become unused
6120 if ($virtdev_hash->{$ds}) {
6121 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6128 # delete vmstate files
6129 # since after the restore we have no snapshots anymore
6130 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6131 my $snap = $oldconf->{snapshots
}->{$snapname};
6132 if ($snap->{vmstate
}) {
6133 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6142 foreach my $virtdev (sort keys %$virtdev_hash) {
6143 my $d = $virtdev_hash->{$virtdev};
6144 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6145 my $storeid = $d->{storeid
};
6146 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6149 if (my $limit = $storage_limits{$storeid}) {
6150 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6153 # test if requested format is supported
6154 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6155 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6156 $d->{format
} = $defFormat if !$supported;
6158 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6159 $d->{format
}, undef, $alloc_size);
6160 print STDERR
"new volume ID is '$volid'\n";
6161 $d->{volid
} = $volid;
6162 my $path = PVE
::Storage
::path
($cfg, $volid);
6164 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6166 my $write_zeros = 1;
6167 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6171 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6173 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6174 $map->{$virtdev} = $volid;
6177 $fh->seek(0, 0) || die "seek failed - $!\n";
6179 my $outfd = new IO
::File
($tmpfn, "w") ||
6180 die "unable to write config for VM $vmid\n";
6182 my $cookie = { netcount
=> 0 };
6183 while (defined(my $line = <$fh>)) {
6184 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6197 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6198 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6200 $oldtimeout = alarm($timeout);
6207 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6208 my ($dev_id, $size, $devname) = ($1, $2, $3);
6209 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6210 } elsif ($line =~ m/^CTIME: /) {
6211 # we correctly received the vma config, so we can disable
6212 # the timeout now for disk allocation (set to 10 minutes, so
6213 # that we always timeout if something goes wrong)
6216 print $fifofh "done\n";
6217 my $tmp = $oldtimeout || 0;
6218 $oldtimeout = undef;
6224 print "restore vma archive: $dbg_cmdstring\n";
6225 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6229 alarm($oldtimeout) if $oldtimeout;
6232 foreach my $devname (keys %$devinfo) {
6233 my $volid = $devinfo->{$devname}->{volid
};
6234 push @$vollist, $volid if $volid;
6237 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6245 foreach my $devname (keys %$devinfo) {
6246 my $volid = $devinfo->{$devname}->{volid
};
6249 if ($volid =~ m
|^/|) {
6250 unlink $volid || die 'unlink failed\n';
6252 PVE
::Storage
::vdisk_free
($cfg, $volid);
6254 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6256 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6263 rename($tmpfn, $conffile) ||
6264 die "unable to commit configuration file '$conffile'\n";
6266 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6268 eval { rescan
($vmid, 1); };
6272 sub restore_tar_archive
{
6273 my ($archive, $vmid, $user, $opts) = @_;
6275 if ($archive ne '-') {
6276 my $firstfile = tar_archive_read_firstfile
($archive);
6277 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6278 if $firstfile ne 'qemu-server.conf';
6281 my $storecfg = PVE
::Storage
::config
();
6283 # destroy existing data - keep empty config
6284 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6285 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6287 my $tocmd = "/usr/lib/qemu-server/qmextract";
6289 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6290 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6291 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6292 $tocmd .= ' --info' if $opts->{info
};
6294 # tar option "xf" does not autodetect compression when read from STDIN,
6295 # so we pipe to zcat
6296 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6297 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6299 my $tmpdir = "/var/tmp/vzdumptmp$$";
6302 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6303 local $ENV{VZDUMP_VMID
} = $vmid;
6304 local $ENV{VZDUMP_USER
} = $user;
6306 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6307 my $tmpfn = "$conffile.$$.tmp";
6309 # disable interrupts (always do cleanups)
6313 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6321 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6323 if ($archive eq '-') {
6324 print "extracting archive from STDIN\n";
6325 run_command
($cmd, input
=> "<&STDIN");
6327 print "extracting archive '$archive'\n";
6331 return if $opts->{info
};
6335 my $statfile = "$tmpdir/qmrestore.stat";
6336 if (my $fd = IO
::File-
>new($statfile, "r")) {
6337 while (defined (my $line = <$fd>)) {
6338 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6339 $map->{$1} = $2 if $1;
6341 print STDERR
"unable to parse line in statfile - $line\n";
6347 my $confsrc = "$tmpdir/qemu-server.conf";
6349 my $srcfd = new IO
::File
($confsrc, "r") ||
6350 die "unable to open file '$confsrc'\n";
6352 my $outfd = new IO
::File
($tmpfn, "w") ||
6353 die "unable to write config for VM $vmid\n";
6355 my $cookie = { netcount
=> 0 };
6356 while (defined (my $line = <$srcfd>)) {
6357 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6369 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6376 rename $tmpfn, $conffile ||
6377 die "unable to commit configuration file '$conffile'\n";
6379 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6381 eval { rescan
($vmid, 1); };
6385 sub foreach_storage_used_by_vm
{
6386 my ($conf, $func) = @_;
6390 foreach_drive
($conf, sub {
6391 my ($ds, $drive) = @_;
6392 return if drive_is_cdrom
($drive);
6394 my $volid = $drive->{file
};
6396 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6397 $sidhash->{$sid} = $sid if $sid;
6400 foreach my $sid (sort keys %$sidhash) {
6405 sub do_snapshots_with_qemu
{
6406 my ($storecfg, $volid) = @_;
6408 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6410 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6411 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6415 if ($volid =~ m/\.(qcow2|qed)$/){
6422 sub qga_check_running
{
6423 my ($vmid, $nowarn) = @_;
6425 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6427 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6433 sub template_create
{
6434 my ($vmid, $conf, $disk) = @_;
6436 my $storecfg = PVE
::Storage
::config
();
6438 foreach_drive
($conf, sub {
6439 my ($ds, $drive) = @_;
6441 return if drive_is_cdrom
($drive);
6442 return if $disk && $ds ne $disk;
6444 my $volid = $drive->{file
};
6445 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6447 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6448 $drive->{file
} = $voliddst;
6449 $conf->{$ds} = print_drive
($vmid, $drive);
6450 PVE
::QemuConfig-
>write_config($vmid, $conf);
6454 sub qemu_img_convert
{
6455 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6457 my $storecfg = PVE
::Storage
::config
();
6458 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6459 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6461 if ($src_storeid && $dst_storeid) {
6463 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6465 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6466 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6468 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6469 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6471 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6472 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6475 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6476 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6477 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6478 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6479 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6480 if ($is_zero_initialized) {
6481 push @$cmd, "zeroinit:$dst_path";
6483 push @$cmd, $dst_path;
6488 if($line =~ m/\((\S+)\/100\
%\)/){
6490 my $transferred = int($size * $percent / 100);
6491 my $remaining = $size - $transferred;
6493 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6498 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6500 die "copy failed: $err" if $err;
6504 sub qemu_img_format
{
6505 my ($scfg, $volname) = @_;
6507 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6514 sub qemu_drive_mirror
{
6515 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6517 $jobs = {} if !$jobs;
6521 $jobs->{"drive-$drive"} = {};
6523 if ($dst_volid =~ /^nbd:/) {
6524 $qemu_target = $dst_volid;
6527 my $storecfg = PVE
::Storage
::config
();
6528 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6530 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6532 $format = qemu_img_format
($dst_scfg, $dst_volname);
6534 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6536 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6539 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6540 $opts->{format
} = $format if $format;
6542 print "drive mirror is starting for drive-$drive\n";
6544 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6547 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6548 die "mirroring error: $err";
6551 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6554 sub qemu_drive_mirror_monitor
{
6555 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6558 my $err_complete = 0;
6561 die "storage migration timed out\n" if $err_complete > 300;
6563 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6565 my $running_mirror_jobs = {};
6566 foreach my $stat (@$stats) {
6567 next if $stat->{type
} ne 'mirror';
6568 $running_mirror_jobs->{$stat->{device
}} = $stat;
6571 my $readycounter = 0;
6573 foreach my $job (keys %$jobs) {
6575 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6576 print "$job : finished\n";
6577 delete $jobs->{$job};
6581 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6583 my $busy = $running_mirror_jobs->{$job}->{busy
};
6584 my $ready = $running_mirror_jobs->{$job}->{ready
};
6585 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6586 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6587 my $remaining = $total - $transferred;
6588 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6590 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6593 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6596 last if scalar(keys %$jobs) == 0;
6598 if ($readycounter == scalar(keys %$jobs)) {
6599 print "all mirroring jobs are ready \n";
6600 last if $skipcomplete; #do the complete later
6602 if ($vmiddst && $vmiddst != $vmid) {
6603 my $agent_running = $qga && qga_check_running
($vmid);
6604 if ($agent_running) {
6605 print "freeze filesystem\n";
6606 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6608 print "suspend vm\n";
6609 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6612 # if we clone a disk for a new target vm, we don't switch the disk
6613 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6615 if ($agent_running) {
6616 print "unfreeze filesystem\n";
6617 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6619 print "resume vm\n";
6620 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6626 foreach my $job (keys %$jobs) {
6627 # try to switch the disk if source and destination are on the same guest
6628 print "$job: Completing block job...\n";
6630 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6631 if ($@ =~ m/cannot be completed/) {
6632 print "$job: Block job cannot be completed, try again.\n";
6635 print "$job: Completed successfully.\n";
6636 $jobs->{$job}->{complete
} = 1;
6647 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6648 die "mirroring error: $err";
6653 sub qemu_blockjobs_cancel
{
6654 my ($vmid, $jobs) = @_;
6656 foreach my $job (keys %$jobs) {
6657 print "$job: Cancelling block job\n";
6658 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6659 $jobs->{$job}->{cancel
} = 1;
6663 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6665 my $running_jobs = {};
6666 foreach my $stat (@$stats) {
6667 $running_jobs->{$stat->{device
}} = $stat;
6670 foreach my $job (keys %$jobs) {
6672 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6673 print "$job: Done.\n";
6674 delete $jobs->{$job};
6678 last if scalar(keys %$jobs) == 0;
6685 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6686 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6691 print "create linked clone of drive $drivename ($drive->{file})\n";
6692 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6693 push @$newvollist, $newvolid;
6696 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6697 $storeid = $storage if $storage;
6699 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6700 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6702 print "create full clone of drive $drivename ($drive->{file})\n";
6704 if (drive_is_cloudinit
($drive)) {
6705 $name = "vm-$newvmid-cloudinit";
6706 # cloudinit only supports raw and qcow2 atm:
6707 if ($dst_format eq 'qcow2') {
6709 } elsif ($dst_format ne 'raw') {
6710 die "clone: unhandled format for cloudinit image\n";
6713 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6714 push @$newvollist, $newvolid;
6716 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6718 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6719 if (!$running || $snapname) {
6720 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6723 my $kvmver = get_running_qemu_version
($vmid);
6724 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6725 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6726 if $drive->{iothread
};
6729 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6733 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6736 $disk->{format
} = undef;
6737 $disk->{file
} = $newvolid;
6738 $disk->{size
} = $size;
6743 # this only works if VM is running
6744 sub get_current_qemu_machine
{
6747 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6748 my $res = vm_qmp_command
($vmid, $cmd);
6750 my ($current, $default);
6751 foreach my $e (@$res) {
6752 $default = $e->{name
} if $e->{'is-default'};
6753 $current = $e->{name
} if $e->{'is-current'};
6756 # fallback to the default machine if current is not supported by qemu
6757 return $current || $default || 'pc';
6760 sub get_running_qemu_version
{
6762 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6763 my $res = vm_qmp_command
($vmid, $cmd);
6764 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6767 sub qemu_machine_feature_enabled
{
6768 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6773 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6775 $current_major = $3;
6776 $current_minor = $4;
6778 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6780 $current_major = $1;
6781 $current_minor = $2;
6784 return 1 if $current_major > $version_major ||
6785 ($current_major == $version_major &&
6786 $current_minor >= $version_minor);
6789 sub qemu_machine_pxe
{
6790 my ($vmid, $conf, $machine) = @_;
6792 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6794 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6801 sub qemu_use_old_bios_files
{
6802 my ($machine_type) = @_;
6804 return if !$machine_type;
6806 my $use_old_bios_files = undef;
6808 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6810 $use_old_bios_files = 1;
6812 my $kvmver = kvm_user_version
();
6813 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6814 # load new efi bios files on migration. So this hack is required to allow
6815 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6816 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6817 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6820 return ($use_old_bios_files, $machine_type);
6823 sub create_efidisk
($$$$$) {
6824 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6826 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6827 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6829 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6830 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6831 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6833 my $path = PVE
::Storage
::path
($storecfg, $volid);
6835 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6837 die "Copying EFI vars image failed: $@" if $@;
6839 return ($volid, $vars_size);
6846 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6847 my (undef, $id, $function) = @_;
6848 my $res = { id
=> $id, function
=> $function};
6849 push @{$devices->{$id}}, $res;
6852 # Entries should be sorted by functions.
6853 foreach my $id (keys %$devices) {
6854 my $dev = $devices->{$id};
6855 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6861 sub vm_iothreads_list
{
6864 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6867 foreach my $iothread (@$res) {
6868 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6875 my ($conf, $drive) = @_;
6879 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6881 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6887 my $controller = int($drive->{index} / $maxdev);
6888 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6890 return ($maxdev, $controller, $controller_prefix);
6893 sub add_hyperv_enlightenments
{
6894 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6896 return if $winversion < 6;
6897 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6899 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6901 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6902 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6903 push @$cpuFlags , 'hv_vapic';
6904 push @$cpuFlags , 'hv_time';
6906 push @$cpuFlags , 'hv_spinlocks=0xffff';
6909 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6910 push @$cpuFlags , 'hv_reset';
6911 push @$cpuFlags , 'hv_vpindex';
6912 push @$cpuFlags , 'hv_runtime';
6915 if ($winversion >= 7) {
6916 push @$cpuFlags , 'hv_relaxed';
6918 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6919 push @$cpuFlags , 'hv_synic';
6920 push @$cpuFlags , 'hv_stimer';
6925 sub windows_version
{
6928 return 0 if !$ostype;
6932 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6934 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6936 } elsif ($ostype =~ m/^win(\d+)$/) {
6943 sub resolve_dst_disk_format
{
6944 my ($storecfg, $storeid, $src_volname, $format) = @_;
6945 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6948 # if no target format is specified, use the source disk format as hint
6950 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6951 $format = qemu_img_format
($scfg, $src_volname);
6957 # test if requested format is supported - else use default
6958 my $supported = grep { $_ eq $format } @$validFormats;
6959 $format = $defFormat if !$supported;
6963 sub resolve_first_disk
{
6965 my @disks = PVE
::QemuServer
::valid_drive_names
();
6967 foreach my $ds (reverse @disks) {
6968 next if !$conf->{$ds};
6969 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6970 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6977 my ($uuid, $uuid_str);
6978 UUID
::generate
($uuid);
6979 UUID
::unparse
($uuid, $uuid_str);
6983 sub generate_smbios1_uuid
{
6984 return "uuid=".generate_uuid
();
6990 vm_mon_cmd
($vmid, 'nbd-server-stop');
6993 # bash completion helper
6995 sub complete_backup_archives
{
6996 my ($cmdname, $pname, $cvalue) = @_;
6998 my $cfg = PVE
::Storage
::config
();
7002 if ($cvalue =~ m/^([^:]+):/) {
7006 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7009 foreach my $id (keys %$data) {
7010 foreach my $item (@{$data->{$id}}) {
7011 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7012 push @$res, $item->{volid
} if defined($item->{volid
});
7019 my $complete_vmid_full = sub {
7022 my $idlist = vmstatus
();
7026 foreach my $id (keys %$idlist) {
7027 my $d = $idlist->{$id};
7028 if (defined($running)) {
7029 next if $d->{template
};
7030 next if $running && $d->{status
} ne 'running';
7031 next if !$running && $d->{status
} eq 'running';
7040 return &$complete_vmid_full();
7043 sub complete_vmid_stopped
{
7044 return &$complete_vmid_full(0);
7047 sub complete_vmid_running
{
7048 return &$complete_vmid_full(1);
7051 sub complete_storage
{
7053 my $cfg = PVE
::Storage
::config
();
7054 my $ids = $cfg->{ids
};
7057 foreach my $sid (keys %$ids) {
7058 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7059 next if !$ids->{$sid}->{content
}->{images
};