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/';
43 my $OVMF_CODE = "$EDK2_FW_BASE/OVMF_CODE.fd";
44 my $OVMF_VARS = "$EDK2_FW_BASE/OVMF_VARS.fd";
46 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
48 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
50 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
52 # Note about locking: we use flock on the config file protect
53 # against concurent actions.
54 # Aditionaly, we have a 'lock' setting in the config file. This
55 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
56 # allowed when such lock is set. But you can ignore this kind of
57 # lock with the --skiplock flag.
59 cfs_register_file
('/qemu-server/',
63 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
64 description
=> "Some command save/restore state from this location.",
70 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
71 description
=> "The name of the snapshot.",
72 type
=> 'string', format
=> 'pve-configid',
76 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
78 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
79 description
=> "The drive's backing file's data format.",
83 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
84 description
=> "Specifies the Qemu machine type.",
86 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
91 #no warnings 'redefine';
94 my ($controller, $vmid, $option, $value) = @_;
96 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
97 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
101 my $nodename = PVE
::INotify
::nodename
();
103 mkdir "/etc/pve/nodes/$nodename";
104 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
107 my $var_run_tmpdir = "/var/run/qemu-server";
108 mkdir $var_run_tmpdir;
110 my $lock_dir = "/var/lock/qemu-server";
113 my $pcisysfs = "/sys/bus/pci";
115 my $cpu_vendor_list = {
117 486 => 'GenuineIntel',
118 pentium
=> 'GenuineIntel',
119 pentium2
=> 'GenuineIntel',
120 pentium3
=> 'GenuineIntel',
121 coreduo
=> 'GenuineIntel',
122 core2duo
=> 'GenuineIntel',
123 Conroe
=> 'GenuineIntel',
124 Penryn
=> 'GenuineIntel',
125 Nehalem
=> 'GenuineIntel',
126 'Nehalem-IBRS' => 'GenuineIntel',
127 Westmere
=> 'GenuineIntel',
128 'Westmere-IBRS' => 'GenuineIntel',
129 SandyBridge
=> 'GenuineIntel',
130 'SandyBridge-IBRS' => 'GenuineIntel',
131 IvyBridge
=> 'GenuineIntel',
132 'IvyBridge-IBRS' => 'GenuineIntel',
133 Haswell
=> 'GenuineIntel',
134 'Haswell-IBRS' => 'GenuineIntel',
135 'Haswell-noTSX' => 'GenuineIntel',
136 'Haswell-noTSX-IBRS' => 'GenuineIntel',
137 Broadwell
=> 'GenuineIntel',
138 'Broadwell-IBRS' => 'GenuineIntel',
139 'Broadwell-noTSX' => 'GenuineIntel',
140 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
141 'Skylake-Client' => 'GenuineIntel',
142 'Skylake-Client-IBRS' => 'GenuineIntel',
143 'Skylake-Server' => 'GenuineIntel',
144 'Skylake-Server-IBRS' => 'GenuineIntel',
147 athlon
=> 'AuthenticAMD',
148 phenom
=> 'AuthenticAMD',
149 Opteron_G1
=> 'AuthenticAMD',
150 Opteron_G2
=> 'AuthenticAMD',
151 Opteron_G3
=> 'AuthenticAMD',
152 Opteron_G4
=> 'AuthenticAMD',
153 Opteron_G5
=> 'AuthenticAMD',
154 EPYC
=> 'AuthenticAMD',
155 'EPYC-IBPB' => 'AuthenticAMD',
157 # generic types, use vendor from host node
166 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
170 description
=> "Emulated CPU type.",
172 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
177 description
=> "Do not identify as a KVM virtual machine.",
183 description
=> "List of additional CPU flags separated by ';'."
184 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
185 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
186 format_description
=> '+FLAG[;-FLAG...]',
188 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
197 enum
=> [qw(i6300esb ib700)],
198 description
=> "Watchdog type to emulate.",
199 default => 'i6300esb',
204 enum
=> [qw(reset shutdown poweroff pause debug none)],
205 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
209 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
213 description
=> "Enable/disable Qemu GuestAgent.",
218 fstrim_cloned_disks
=> {
219 description
=> "Run fstrim after cloning/moving a disk.",
230 description
=> "Specifies whether a VM will be started during system bootup.",
236 description
=> "Automatic restart after crash (currently ignored).",
241 type
=> 'string', format
=> 'pve-hotplug-features',
242 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'.",
243 default => 'network,disk,usb',
248 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
254 description
=> "Lock/unlock the VM.",
255 enum
=> [qw(migrate backup snapshot rollback)],
260 description
=> "Limit of CPU usage.",
261 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.",
269 description
=> "CPU weight for a VM.",
270 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.",
278 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
285 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
291 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.",
299 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
300 "It should not be necessary to set it.",
301 enum
=> PVE
::Tools
::kvmkeymaplist
(),
306 type
=> 'string', format
=> 'dns-name',
307 description
=> "Set a name for the VM. Only used on the configuration web interface.",
312 description
=> "SCSI controller model",
313 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
319 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
324 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
325 description
=> "Specify guest operating system.",
326 verbose_description
=> <<EODESC,
327 Specify guest operating system. This is used to enable special
328 optimization/features for specific operating systems:
331 other;; unspecified OS
332 wxp;; Microsoft Windows XP
333 w2k;; Microsoft Windows 2000
334 w2k3;; Microsoft Windows 2003
335 w2k8;; Microsoft Windows 2008
336 wvista;; Microsoft Windows Vista
337 win7;; Microsoft Windows 7
338 win8;; Microsoft Windows 8/2012/2012r2
339 win10;; Microsoft Windows 10/2016
340 l24;; Linux 2.4 Kernel
341 l26;; Linux 2.6/3.X Kernel
342 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
348 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
349 pattern
=> '[acdn]{1,4}',
354 type
=> 'string', format
=> 'pve-qm-bootdisk',
355 description
=> "Enable booting from specified disk.",
356 pattern
=> '(ide|sata|scsi|virtio)\d+',
361 description
=> "The number of CPUs. Please use option -sockets instead.",
368 description
=> "The number of CPU sockets.",
375 description
=> "The number of cores per socket.",
382 description
=> "Enable/disable NUMA.",
388 description
=> "Enable/disable hugepages memory.",
389 enum
=> [qw(any 2 1024)],
394 description
=> "Number of hotplugged vcpus.",
401 description
=> "Enable/disable ACPI.",
406 description
=> "Enable/disable Qemu GuestAgent and its properties.",
408 format
=> $agent_fmt,
413 description
=> "Enable/disable KVM hardware virtualization.",
419 description
=> "Enable/disable time drift fix.",
425 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
430 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
435 description
=> "Select the VGA type.",
436 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
437 " modes (>= 1280x1024x16) then you should use the options " .
438 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
439 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
440 "display sever. For win* OS you can select how many independent " .
441 "displays you want, Linux guests can add displays them self. " .
442 "You can also run without any graphic card, using a serial device" .
444 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 serial0 serial1 serial2 serial3 std virtio vmware)],
448 type
=> 'string', format
=> 'pve-qm-watchdog',
449 description
=> "Create a virtual hardware watchdog device.",
450 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
451 " (by a guest action), the watchdog must be periodically polled " .
452 "by an agent inside the guest or else the watchdog will reset " .
453 "the guest (or execute the respective action specified)",
458 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
459 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'.",
460 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
463 startup
=> get_standard_option
('pve-startup-order'),
467 description
=> "Enable/disable Template.",
473 description
=> "Arbitrary arguments passed to kvm.",
474 verbose_description
=> <<EODESCR,
475 Arbitrary arguments passed to kvm, for example:
477 args: -no-reboot -no-hpet
479 NOTE: this option is for experts only.
486 description
=> "Enable/disable the USB tablet device.",
487 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
488 "usually needed to allow absolute mouse positioning with VNC. " .
489 "Else the mouse runs out of sync with normal VNC clients. " .
490 "If you're running lots of console-only guests on one host, " .
491 "you may consider disabling this to save some context switches. " .
492 "This is turned off by default if you use spice (-vga=qxl).",
497 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
501 migrate_downtime
=> {
504 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
510 type
=> 'string', format
=> 'pve-qm-ide',
511 typetext
=> '<volume>',
512 description
=> "This is an alias for option -ide2",
516 description
=> "Emulated CPU type.",
520 parent
=> get_standard_option
('pve-snapshot-name', {
522 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
526 description
=> "Timestamp for snapshots.",
532 type
=> 'string', format
=> 'pve-volume-id',
533 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
535 vmstatestorage
=> get_standard_option
('pve-storage-id', {
536 description
=> "Default storage for VM state volumes/files.",
539 runningmachine
=> get_standard_option
('pve-qemu-machine', {
540 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
542 machine
=> get_standard_option
('pve-qemu-machine'),
544 description
=> "Specify SMBIOS type 1 fields.",
545 type
=> 'string', format
=> 'pve-qm-smbios1',
552 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
558 enum
=> [ qw(seabios ovmf) ],
559 description
=> "Select BIOS implementation.",
560 default => 'seabios',
564 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
565 format_description
=> 'UUID',
566 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
567 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
568 " 128-bit integer value identifier to the guest OS. This allows to".
569 " notify the guest operating system when the virtual machine is".
570 " executed with a different configuration (e.g. snapshot execution".
571 " or creation from a template). The guest operating system notices".
572 " the change, and is then able to react as appropriate by marking".
573 " its copies of distributed databases as dirty, re-initializing its".
574 " random number generator, etc.\n".
575 "Note that auto-creation only works when done throug API/CLI create".
576 " or update methods, but not when manually editing the config file.",
577 default => "1 (autogenerated)",
582 my $confdesc_cloudinit = {
586 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.',
587 enum
=> ['configdrive2', 'nocloud'],
592 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
597 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.',
602 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.",
606 type
=> 'string', format
=> 'address-list',
607 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.",
612 format
=> 'urlencoded',
613 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
617 # what about other qemu settings ?
619 #machine => 'string',
632 ##soundhw => 'string',
634 while (my ($k, $v) = each %$confdesc) {
635 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
638 my $MAX_IDE_DISKS = 4;
639 my $MAX_SCSI_DISKS = 14;
640 my $MAX_VIRTIO_DISKS = 16;
641 my $MAX_SATA_DISKS = 6;
642 my $MAX_USB_DEVICES = 5;
644 my $MAX_UNUSED_DISKS = 8;
645 my $MAX_HOSTPCI_DEVICES = 4;
646 my $MAX_SERIAL_PORTS = 4;
647 my $MAX_PARALLEL_PORTS = 3;
653 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
654 description
=> "CPUs accessing this NUMA node.",
655 format_description
=> "id[-id];...",
659 description
=> "Amount of memory this NUMA node provides.",
664 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
665 description
=> "Host NUMA nodes to use.",
666 format_description
=> "id[-id];...",
671 enum
=> [qw(preferred bind interleave)],
672 description
=> "NUMA allocation policy.",
676 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
679 type
=> 'string', format
=> $numa_fmt,
680 description
=> "NUMA topology.",
682 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
684 for (my $i = 0; $i < $MAX_NUMA; $i++) {
685 $confdesc->{"numa$i"} = $numadesc;
688 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
689 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
690 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
691 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
693 my $net_fmt_bridge_descr = <<__EOD__;
694 Bridge to attach the network device to. The Proxmox VE standard bridge
697 If you do not specify a bridge, we create a kvm user (NATed) network
698 device, which provides DHCP and DNS services. The following addresses
705 The DHCP server assign addresses to the guest starting from 10.0.2.15.
711 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
712 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
713 format_description
=> "XX:XX:XX:XX:XX:XX",
718 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'.",
719 enum
=> $nic_model_list,
722 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
725 description
=> $net_fmt_bridge_descr,
726 format_description
=> 'bridge',
731 minimum
=> 0, maximum
=> 16,
732 description
=> 'Number of packet queues to be used on the device.',
738 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
743 minimum
=> 1, maximum
=> 4094,
744 description
=> 'VLAN tag to apply to packets on this interface.',
749 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
750 description
=> 'VLAN trunks to pass through this interface.',
751 format_description
=> 'vlanid[;vlanid...]',
756 description
=> 'Whether this interface should be protected by the firewall.',
761 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
768 type
=> 'string', format
=> $net_fmt,
769 description
=> "Specify network devices.",
772 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
777 format
=> 'pve-ipv4-config',
778 format_description
=> 'IPv4Format/CIDR',
779 description
=> 'IPv4 address in CIDR format.',
786 format_description
=> 'GatewayIPv4',
787 description
=> 'Default gateway for IPv4 traffic.',
793 format
=> 'pve-ipv6-config',
794 format_description
=> 'IPv6Format/CIDR',
795 description
=> 'IPv6 address in CIDR format.',
802 format_description
=> 'GatewayIPv6',
803 description
=> 'Default gateway for IPv6 traffic.',
808 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
811 type
=> 'string', format
=> 'pve-qm-ipconfig',
812 description
=> <<'EODESCR',
813 cloud-init: Specify IP addresses and gateways for the corresponding interface.
815 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
817 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
818 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
820 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
823 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
825 for (my $i = 0; $i < $MAX_NETS; $i++) {
826 $confdesc->{"net$i"} = $netdesc;
827 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
830 foreach my $key (keys %$confdesc_cloudinit) {
831 $confdesc->{$key} = $confdesc_cloudinit->{$key};
834 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
835 sub verify_volume_id_or_qm_path
{
836 my ($volid, $noerr) = @_;
838 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
842 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
843 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
845 return undef if $noerr;
853 my %drivedesc_base = (
854 volume
=> { alias
=> 'file' },
857 format
=> 'pve-volume-id-or-qm-path',
859 format_description
=> 'volume',
860 description
=> "The drive's backing volume.",
864 enum
=> [qw(cdrom disk)],
865 description
=> "The drive's media type.",
871 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
876 description
=> "Force the drive's physical geometry to have a specific head count.",
881 description
=> "Force the drive's physical geometry to have a specific sector count.",
886 enum
=> [qw(none lba auto)],
887 description
=> "Force disk geometry bios translation mode.",
892 description
=> "Controls qemu's snapshot mode feature."
893 . " If activated, changes made to the disk are temporary and will"
894 . " be discarded when the VM is shutdown.",
899 enum
=> [qw(none writethrough writeback unsafe directsync)],
900 description
=> "The drive's cache mode",
903 format
=> get_standard_option
('pve-qm-image-format'),
906 format
=> 'disk-size',
907 format_description
=> 'DiskSize',
908 description
=> "Disk size. This is purely informational and has no effect.",
913 description
=> "Whether the drive should be included when making backups.",
918 description
=> 'Whether the drive should considered for replication jobs.',
924 enum
=> [qw(ignore report stop)],
925 description
=> 'Read error action.',
930 enum
=> [qw(enospc ignore report stop)],
931 description
=> 'Write error action.',
936 enum
=> [qw(native threads)],
937 description
=> 'AIO type to use.',
942 enum
=> [qw(ignore on)],
943 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
948 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
953 format
=> 'urlencoded',
954 format_description
=> 'serial',
955 maxLength
=> 20*3, # *3 since it's %xx url enoded
956 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
961 description
=> 'Mark this locally-managed volume as available on all nodes',
962 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!",
968 my %iothread_fmt = ( iothread
=> {
970 description
=> "Whether to use iothreads for this drive",
977 format
=> 'urlencoded',
978 format_description
=> 'model',
979 maxLength
=> 40*3, # *3 since it's %xx url enoded
980 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
988 description
=> "Number of queues.",
994 my %scsiblock_fmt = (
997 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",
1003 my $add_throttle_desc = sub {
1004 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1007 format_description
=> $unit,
1008 description
=> "Maximum $what in $longunit.",
1011 $d->{minimum
} = $minimum if defined($minimum);
1012 $drivedesc_base{$key} = $d;
1014 # throughput: (leaky bucket)
1015 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1016 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1017 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1018 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1019 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1020 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1021 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1022 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1023 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1025 # pools: (pool of IO before throttling starts taking effect)
1026 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1027 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1028 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1029 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1030 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1031 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1034 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1035 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1036 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1037 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1038 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1039 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1042 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1043 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1044 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1045 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1051 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1055 type
=> 'string', format
=> $ide_fmt,
1056 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1058 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1068 type
=> 'string', format
=> $scsi_fmt,
1069 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1071 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1078 type
=> 'string', format
=> $sata_fmt,
1079 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1081 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1089 type
=> 'string', format
=> $virtio_fmt,
1090 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1092 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1094 my $alldrive_fmt = {
1103 volume
=> { alias
=> 'file' },
1106 format
=> 'pve-volume-id-or-qm-path',
1108 format_description
=> 'volume',
1109 description
=> "The drive's backing volume.",
1111 format
=> get_standard_option
('pve-qm-image-format'),
1114 format
=> 'disk-size',
1115 format_description
=> 'DiskSize',
1116 description
=> "Disk size. This is purely informational and has no effect.",
1121 my $efidisk_desc = {
1123 type
=> 'string', format
=> $efidisk_fmt,
1124 description
=> "Configure a Disk for storing EFI vars",
1127 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1132 type
=> 'string', format
=> 'pve-qm-usb-device',
1133 format_description
=> 'HOSTUSBDEVICE|spice',
1134 description
=> <<EODESCR,
1135 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1137 'bus-port(.port)*' (decimal numbers) or
1138 'vendor_id:product_id' (hexadeciaml numbers) or
1141 You can use the 'lsusb -t' command to list existing usb devices.
1143 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1145 The value 'spice' can be used to add a usb redirection devices for spice.
1151 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).",
1158 type
=> 'string', format
=> $usb_fmt,
1159 description
=> "Configure an USB device (n is 0 to 4).",
1161 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1163 # NOTE: the match-groups of this regex are used in parse_hostpci
1164 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1169 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1170 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1171 description
=> <<EODESCR,
1172 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1173 of PCI virtual functions of the host. HOSTPCIID syntax is:
1175 'bus:dev.func' (hexadecimal numbers)
1177 You can us the 'lspci' command to list existing PCI devices.
1182 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1188 pattern
=> '[^,;]+',
1189 format_description
=> 'string',
1190 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1195 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1201 description
=> "Enable vfio-vga device support.",
1206 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1210 type
=> 'string', format
=> 'pve-qm-hostpci',
1211 description
=> "Map host PCI devices into guest.",
1212 verbose_description
=> <<EODESCR,
1213 Map host PCI devices into guest.
1215 NOTE: This option allows direct access to host hardware. So it is no longer
1216 possible to migrate such machines - use with special care.
1218 CAUTION: Experimental! User reported problems with this option.
1221 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1226 pattern
=> '(/dev/.+|socket)',
1227 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1228 verbose_description
=> <<EODESCR,
1229 Create a serial device inside the VM (n is 0 to 3), and pass through a
1230 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1231 host side (use 'qm terminal' to open a terminal connection).
1233 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1235 CAUTION: Experimental! User reported problems with this option.
1242 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1243 description
=> "Map host parallel devices (n is 0 to 2).",
1244 verbose_description
=> <<EODESCR,
1245 Map host parallel devices (n is 0 to 2).
1247 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1249 CAUTION: Experimental! User reported problems with this option.
1253 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1254 $confdesc->{"parallel$i"} = $paralleldesc;
1257 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1258 $confdesc->{"serial$i"} = $serialdesc;
1261 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1262 $confdesc->{"hostpci$i"} = $hostpcidesc;
1265 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1266 $drivename_hash->{"ide$i"} = 1;
1267 $confdesc->{"ide$i"} = $idedesc;
1270 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1271 $drivename_hash->{"sata$i"} = 1;
1272 $confdesc->{"sata$i"} = $satadesc;
1275 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1276 $drivename_hash->{"scsi$i"} = 1;
1277 $confdesc->{"scsi$i"} = $scsidesc ;
1280 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1281 $drivename_hash->{"virtio$i"} = 1;
1282 $confdesc->{"virtio$i"} = $virtiodesc;
1285 $drivename_hash->{efidisk0
} = 1;
1286 $confdesc->{efidisk0
} = $efidisk_desc;
1288 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1289 $confdesc->{"usb$i"} = $usbdesc;
1294 type
=> 'string', format
=> 'pve-volume-id',
1295 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1298 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1299 $confdesc->{"unused$i"} = $unuseddesc;
1302 my $kvm_api_version = 0;
1306 return $kvm_api_version if $kvm_api_version;
1308 my $fh = IO
::File-
>new("</dev/kvm") ||
1311 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1312 $kvm_api_version = $v;
1317 return $kvm_api_version;
1320 my $kvm_user_version;
1322 sub kvm_user_version
{
1324 return $kvm_user_version if $kvm_user_version;
1326 $kvm_user_version = 'unknown';
1330 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1331 $kvm_user_version = $2;
1335 eval { run_command
("kvm -version", outfunc
=> $code); };
1338 return $kvm_user_version;
1342 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1344 sub valid_drive_names
{
1345 # order is important - used to autoselect boot disk
1346 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1347 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1348 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1349 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1353 sub is_valid_drivename
{
1356 return defined($drivename_hash->{$dev});
1361 return defined($confdesc->{$key});
1365 return $nic_model_list;
1368 sub os_list_description
{
1372 wxp
=> 'Windows XP',
1373 w2k
=> 'Windows 2000',
1374 w2k3
=>, 'Windows 2003',
1375 w2k8
=> 'Windows 2008',
1376 wvista
=> 'Windows Vista',
1377 win7
=> 'Windows 7',
1378 win8
=> 'Windows 8/2012',
1379 win10
=> 'Windows 10/2016',
1387 sub get_cdrom_path
{
1389 return $cdrom_path if $cdrom_path;
1391 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1392 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1393 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1397 my ($storecfg, $vmid, $cdrom) = @_;
1399 if ($cdrom eq 'cdrom') {
1400 return get_cdrom_path
();
1401 } elsif ($cdrom eq 'none') {
1403 } elsif ($cdrom =~ m
|^/|) {
1406 return PVE
::Storage
::path
($storecfg, $cdrom);
1410 # try to convert old style file names to volume IDs
1411 sub filename_to_volume_id
{
1412 my ($vmid, $file, $media) = @_;
1414 if (!($file eq 'none' || $file eq 'cdrom' ||
1415 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1417 return undef if $file =~ m
|/|;
1419 if ($media && $media eq 'cdrom') {
1420 $file = "local:iso/$file";
1422 $file = "local:$vmid/$file";
1429 sub verify_media_type
{
1430 my ($opt, $vtype, $media) = @_;
1435 if ($media eq 'disk') {
1437 } elsif ($media eq 'cdrom') {
1440 die "internal error";
1443 return if ($vtype eq $etype);
1445 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1448 sub cleanup_drive_path
{
1449 my ($opt, $storecfg, $drive) = @_;
1451 # try to convert filesystem paths to volume IDs
1453 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1454 ($drive->{file
} !~ m
|^/dev/.+|) &&
1455 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1456 ($drive->{file
} !~ m/^\d+$/)) {
1457 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1458 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1459 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1460 verify_media_type
($opt, $vtype, $drive->{media
});
1461 $drive->{file
} = $volid;
1464 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1467 sub parse_hotplug_features
{
1472 return $res if $data eq '0';
1474 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1476 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1477 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1480 die "invalid hotplug feature '$feature'\n";
1486 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1487 sub pve_verify_hotplug_features
{
1488 my ($value, $noerr) = @_;
1490 return $value if parse_hotplug_features
($value);
1492 return undef if $noerr;
1494 die "unable to parse hotplug option\n";
1497 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1498 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1499 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1500 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1501 # [,iothread=on][,serial=serial][,model=model]
1504 my ($key, $data) = @_;
1506 my ($interface, $index);
1508 if ($key =~ m/^([^\d]+)(\d+)$/) {
1515 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1516 : $confdesc->{$key}->{format
};
1518 warn "invalid drive key: $key\n";
1521 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1522 return undef if !$res;
1523 $res->{interface
} = $interface;
1524 $res->{index} = $index;
1527 foreach my $opt (qw(bps bps_rd bps_wr)) {
1528 if (my $bps = defined(delete $res->{$opt})) {
1529 if (defined($res->{"m$opt"})) {
1530 warn "both $opt and m$opt specified\n";
1534 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1538 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1539 for my $requirement (
1540 [mbps_max
=> 'mbps'],
1541 [mbps_rd_max
=> 'mbps_rd'],
1542 [mbps_wr_max
=> 'mbps_wr'],
1543 [miops_max
=> 'miops'],
1544 [miops_rd_max
=> 'miops_rd'],
1545 [miops_wr_max
=> 'miops_wr'],
1546 [bps_max_length
=> 'mbps_max'],
1547 [bps_rd_max_length
=> 'mbps_rd_max'],
1548 [bps_wr_max_length
=> 'mbps_wr_max'],
1549 [iops_max_length
=> 'iops_max'],
1550 [iops_rd_max_length
=> 'iops_rd_max'],
1551 [iops_wr_max_length
=> 'iops_wr_max']) {
1552 my ($option, $requires) = @$requirement;
1553 if ($res->{$option} && !$res->{$requires}) {
1554 warn "$option requires $requires\n";
1559 return undef if $error;
1561 return undef if $res->{mbps_rd
} && $res->{mbps
};
1562 return undef if $res->{mbps_wr
} && $res->{mbps
};
1563 return undef if $res->{iops_rd
} && $res->{iops
};
1564 return undef if $res->{iops_wr
} && $res->{iops
};
1566 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1567 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1568 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1569 return undef if $res->{interface
} eq 'virtio';
1572 if (my $size = $res->{size
}) {
1573 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1580 my ($vmid, $drive) = @_;
1581 my $data = { %$drive };
1582 delete $data->{$_} for qw(index interface);
1583 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1587 my($fh, $noerr) = @_;
1590 my $SG_GET_VERSION_NUM = 0x2282;
1592 my $versionbuf = "\x00" x
8;
1593 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1595 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1598 my $version = unpack("I", $versionbuf);
1599 if ($version < 30000) {
1600 die "scsi generic interface too old\n" if !$noerr;
1604 my $buf = "\x00" x
36;
1605 my $sensebuf = "\x00" x
8;
1606 my $cmd = pack("C x3 C x1", 0x12, 36);
1608 # see /usr/include/scsi/sg.h
1609 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";
1611 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1612 length($sensebuf), 0, length($buf), $buf,
1613 $cmd, $sensebuf, 6000);
1615 $ret = ioctl($fh, $SG_IO, $packet);
1617 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1621 my @res = unpack($sg_io_hdr_t, $packet);
1622 if ($res[17] || $res[18]) {
1623 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1628 (my $byte0, my $byte1, $res->{vendor
},
1629 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1631 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1632 $res->{type
} = $byte0 & 31;
1640 my $fh = IO
::File-
>new("+<$path") || return undef;
1641 my $res = scsi_inquiry
($fh, 1);
1647 sub machine_type_is_q35
{
1650 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1653 sub print_tabletdevice_full
{
1656 my $q35 = machine_type_is_q35
($conf);
1658 # we use uhci for old VMs because tablet driver was buggy in older qemu
1659 my $usbbus = $q35 ?
"ehci" : "uhci";
1661 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1664 sub print_drivedevice_full
{
1665 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1670 if ($drive->{interface
} eq 'virtio') {
1671 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1672 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1673 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1674 } elsif ($drive->{interface
} eq 'scsi') {
1676 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1677 my $unit = $drive->{index} % $maxdev;
1678 my $devicetype = 'hd';
1680 if (drive_is_cdrom
($drive)) {
1683 if ($drive->{file
} =~ m
|^/|) {
1684 $path = $drive->{file
};
1685 if (my $info = path_is_scsi
($path)) {
1686 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1687 $devicetype = 'block';
1688 } elsif ($info->{type
} == 1) { # tape
1689 $devicetype = 'generic';
1693 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1696 if($path =~ m/^iscsi\:\/\
//){
1697 $devicetype = 'generic';
1701 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1702 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1704 $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}";
1707 } elsif ($drive->{interface
} eq 'ide'){
1709 my $controller = int($drive->{index} / $maxdev);
1710 my $unit = $drive->{index} % $maxdev;
1711 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1713 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1714 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1715 $model = URI
::Escape
::uri_unescape
($model);
1716 $device .= ",model=$model";
1718 } elsif ($drive->{interface
} eq 'sata'){
1719 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1720 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1721 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1722 } elsif ($drive->{interface
} eq 'usb') {
1724 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1726 die "unsupported interface type";
1729 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1731 if (my $serial = $drive->{serial
}) {
1732 $serial = URI
::Escape
::uri_unescape
($serial);
1733 $device .= ",serial=$serial";
1740 sub get_initiator_name
{
1743 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1744 while (defined(my $line = <$fh>)) {
1745 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1754 sub print_drive_full
{
1755 my ($storecfg, $vmid, $drive) = @_;
1758 my $volid = $drive->{file
};
1761 if (drive_is_cdrom
($drive)) {
1762 $path = get_iso_path
($storecfg, $vmid, $volid);
1764 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1766 $path = PVE
::Storage
::path
($storecfg, $volid);
1767 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1768 $format = qemu_img_format
($scfg, $volname);
1776 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1777 foreach my $o (@qemu_drive_options) {
1778 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1781 # snapshot only accepts on|off
1782 if (defined($drive->{snapshot
})) {
1783 my $v = $drive->{snapshot
} ?
'on' : 'off';
1784 $opts .= ",snapshot=$v";
1787 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1788 my ($dir, $qmpname) = @$type;
1789 if (my $v = $drive->{"mbps$dir"}) {
1790 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1792 if (my $v = $drive->{"mbps${dir}_max"}) {
1793 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1795 if (my $v = $drive->{"bps${dir}_max_length"}) {
1796 $opts .= ",throttling.bps$qmpname-max-length=$v";
1798 if (my $v = $drive->{"iops${dir}"}) {
1799 $opts .= ",throttling.iops$qmpname=$v";
1801 if (my $v = $drive->{"iops${dir}_max"}) {
1802 $opts .= ",throttling.iops$qmpname-max=$v";
1804 if (my $v = $drive->{"iops${dir}_max_length"}) {
1805 $opts .= ",throttling.iops$qmpname-max-length=$v";
1809 $opts .= ",format=$format" if $format && !$drive->{format
};
1811 my $cache_direct = 0;
1813 if (my $cache = $drive->{cache
}) {
1814 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1815 } elsif (!drive_is_cdrom
($drive)) {
1816 $opts .= ",cache=none";
1820 # aio native works only with O_DIRECT
1821 if (!$drive->{aio
}) {
1823 $opts .= ",aio=native";
1825 $opts .= ",aio=threads";
1829 if (!drive_is_cdrom
($drive)) {
1831 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1832 $detectzeroes = 'off';
1833 } elsif ($drive->{discard
}) {
1834 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1836 # This used to be our default with discard not being specified:
1837 $detectzeroes = 'on';
1839 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1842 my $pathinfo = $path ?
"file=$path," : '';
1844 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1847 sub print_netdevice_full
{
1848 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1850 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1852 my $device = $net->{model
};
1853 if ($net->{model
} eq 'virtio') {
1854 $device = 'virtio-net-pci';
1857 my $pciaddr = print_pci_addr
("$netid", $bridges);
1858 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1859 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1860 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1861 my $vectors = $net->{queues
} * 2 + 2;
1862 $tmpstr .= ",vectors=$vectors,mq=on";
1864 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1866 if ($use_old_bios_files) {
1868 if ($device eq 'virtio-net-pci') {
1869 $romfile = 'pxe-virtio.rom';
1870 } elsif ($device eq 'e1000') {
1871 $romfile = 'pxe-e1000.rom';
1872 } elsif ($device eq 'ne2k') {
1873 $romfile = 'pxe-ne2k_pci.rom';
1874 } elsif ($device eq 'pcnet') {
1875 $romfile = 'pxe-pcnet.rom';
1876 } elsif ($device eq 'rtl8139') {
1877 $romfile = 'pxe-rtl8139.rom';
1879 $tmpstr .= ",romfile=$romfile" if $romfile;
1885 sub print_netdev_full
{
1886 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1889 if ($netid =~ m/^net(\d+)$/) {
1893 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1895 my $ifname = "tap${vmid}i$i";
1897 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1898 die "interface name '$ifname' is too long (max 15 character)\n"
1899 if length($ifname) >= 16;
1901 my $vhostparam = '';
1902 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1904 my $vmname = $conf->{name
} || "vm$vmid";
1907 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1909 if ($net->{bridge
}) {
1910 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1912 $netdev = "type=user,id=$netid,hostname=$vmname";
1915 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1921 sub print_cpu_device
{
1922 my ($conf, $id) = @_;
1924 my $kvm = $conf->{kvm
} // 1;
1925 my $cpu = $kvm ?
"kvm64" : "qemu64";
1926 if (my $cputype = $conf->{cpu
}) {
1927 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1928 or die "Cannot parse cpu description: $cputype\n";
1929 $cpu = $cpuconf->{cputype
};
1932 my $cores = $conf->{cores
} || 1;
1934 my $current_core = ($id - 1) % $cores;
1935 my $current_socket = int(($id - 1 - $current_core)/$cores);
1937 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1940 sub drive_is_cloudinit
{
1942 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1945 sub drive_is_cdrom
{
1946 my ($drive, $exclude_cloudinit) = @_;
1948 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1950 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1954 sub parse_number_sets
{
1957 foreach my $part (split(/;/, $set)) {
1958 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1959 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1960 push @$res, [ $1, $2 ];
1962 die "invalid range: $part\n";
1971 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1972 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1973 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1980 return undef if !$value;
1982 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1984 my @idlist = split(/;/, $res->{host
});
1985 delete $res->{host
};
1986 foreach my $id (@idlist) {
1987 if ($id =~ /^$PCIRE$/) {
1989 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1991 my $pcidevices = lspci
($1);
1992 $res->{pciid
} = $pcidevices->{$1};
1995 # should have been caught by parse_property_string already
1996 die "failed to parse PCI id: $id\n";
2002 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2006 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2011 if (!defined($res->{macaddr
})) {
2012 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2013 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2018 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2019 sub parse_ipconfig
{
2022 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2028 if ($res->{gw
} && !$res->{ip
}) {
2029 warn 'gateway specified without specifying an IP address';
2032 if ($res->{gw6
} && !$res->{ip6
}) {
2033 warn 'IPv6 gateway specified without specifying an IPv6 address';
2036 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2037 warn 'gateway specified together with DHCP';
2040 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2042 warn "IPv6 gateway specified together with $res->{ip6} address";
2046 if (!$res->{ip
} && !$res->{ip6
}) {
2047 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2056 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2059 sub add_random_macs
{
2060 my ($settings) = @_;
2062 foreach my $opt (keys %$settings) {
2063 next if $opt !~ m/^net(\d+)$/;
2064 my $net = parse_net
($settings->{$opt});
2066 $settings->{$opt} = print_net
($net);
2070 sub vm_is_volid_owner
{
2071 my ($storecfg, $vmid, $volid) = @_;
2073 if ($volid !~ m
|^/|) {
2075 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2076 if ($owner && ($owner == $vmid)) {
2084 sub split_flagged_list
{
2085 my $text = shift || '';
2086 $text =~ s/[,;]/ /g;
2088 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2091 sub join_flagged_list
{
2092 my ($how, $lst) = @_;
2093 join $how, map { $lst->{$_} . $_ } keys %$lst;
2096 sub vmconfig_delete_pending_option
{
2097 my ($conf, $key, $force) = @_;
2099 delete $conf->{pending
}->{$key};
2100 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2101 $pending_delete_hash->{$key} = $force ?
'!' : '';
2102 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2105 sub vmconfig_undelete_pending_option
{
2106 my ($conf, $key) = @_;
2108 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2109 delete $pending_delete_hash->{$key};
2111 if (%$pending_delete_hash) {
2112 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2114 delete $conf->{pending
}->{delete};
2118 sub vmconfig_register_unused_drive
{
2119 my ($storecfg, $vmid, $conf, $drive) = @_;
2121 if (drive_is_cloudinit
($drive)) {
2122 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2124 } elsif (!drive_is_cdrom
($drive)) {
2125 my $volid = $drive->{file
};
2126 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2127 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2132 sub vmconfig_cleanup_pending
{
2135 # remove pending changes when nothing changed
2137 foreach my $opt (keys %{$conf->{pending
}}) {
2138 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2140 delete $conf->{pending
}->{$opt};
2144 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2145 my $pending_delete_hash = {};
2146 while (my ($opt, $force) = each %$current_delete_hash) {
2147 if (defined($conf->{$opt})) {
2148 $pending_delete_hash->{$opt} = $force;
2154 if (%$pending_delete_hash) {
2155 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2157 delete $conf->{pending
}->{delete};
2163 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2167 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2168 format_description
=> 'UUID',
2169 description
=> "Set SMBIOS1 UUID.",
2175 format_description
=> 'string',
2176 description
=> "Set SMBIOS1 version.",
2182 format_description
=> 'string',
2183 description
=> "Set SMBIOS1 serial number.",
2189 format_description
=> 'string',
2190 description
=> "Set SMBIOS1 manufacturer.",
2196 format_description
=> 'string',
2197 description
=> "Set SMBIOS1 product ID.",
2203 format_description
=> 'string',
2204 description
=> "Set SMBIOS1 SKU string.",
2210 format_description
=> 'string',
2211 description
=> "Set SMBIOS1 family string.",
2219 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2226 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2229 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2231 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2232 sub verify_bootdisk
{
2233 my ($value, $noerr) = @_;
2235 return $value if is_valid_drivename
($value);
2237 return undef if $noerr;
2239 die "invalid boot disk '$value'\n";
2242 sub parse_watchdog
{
2245 return undef if !$value;
2247 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2252 sub parse_guest_agent
{
2255 return {} if !defined($value->{agent
});
2257 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2260 # if the agent is disabled ignore the other potentially set properties
2261 return {} if !$res->{enabled
};
2265 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2266 sub verify_usb_device
{
2267 my ($value, $noerr) = @_;
2269 return $value if parse_usb_device
($value);
2271 return undef if $noerr;
2273 die "unable to parse usb device\n";
2276 # add JSON properties for create and set function
2277 sub json_config_properties
{
2280 foreach my $opt (keys %$confdesc) {
2281 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2282 $prop->{$opt} = $confdesc->{$opt};
2288 # return copy of $confdesc_cloudinit to generate documentation
2289 sub cloudinit_config_properties
{
2291 return dclone
($confdesc_cloudinit);
2295 my ($key, $value) = @_;
2297 die "unknown setting '$key'\n" if !$confdesc->{$key};
2299 my $type = $confdesc->{$key}->{type
};
2301 if (!defined($value)) {
2302 die "got undefined value\n";
2305 if ($value =~ m/[\n\r]/) {
2306 die "property contains a line feed\n";
2309 if ($type eq 'boolean') {
2310 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2311 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2312 die "type check ('boolean') failed - got '$value'\n";
2313 } elsif ($type eq 'integer') {
2314 return int($1) if $value =~ m/^(\d+)$/;
2315 die "type check ('integer') failed - got '$value'\n";
2316 } elsif ($type eq 'number') {
2317 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2318 die "type check ('number') failed - got '$value'\n";
2319 } elsif ($type eq 'string') {
2320 if (my $fmt = $confdesc->{$key}->{format
}) {
2321 PVE
::JSONSchema
::check_format
($fmt, $value);
2324 $value =~ s/^\"(.*)\"$/$1/;
2327 die "internal error"
2331 sub check_iommu_support
{
2332 #fixme : need to check IOMMU support
2333 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2343 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2344 utime undef, undef, $conf;
2348 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2350 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2352 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2354 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2356 if ($conf->{template
}) {
2357 # check if any base image is still used by a linked clone
2358 foreach_drive
($conf, sub {
2359 my ($ds, $drive) = @_;
2361 return if drive_is_cdrom
($drive);
2363 my $volid = $drive->{file
};
2365 return if !$volid || $volid =~ m
|^/|;
2367 die "base volume '$volid' is still in use by linked cloned\n"
2368 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2373 # only remove disks owned by this VM
2374 foreach_drive
($conf, sub {
2375 my ($ds, $drive) = @_;
2377 return if drive_is_cdrom
($drive, 1);
2379 my $volid = $drive->{file
};
2381 return if !$volid || $volid =~ m
|^/|;
2383 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2384 return if !$path || !$owner || ($owner != $vmid);
2387 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2389 warn "Could not remove disk '$volid', check manually: $@" if $@;
2393 if ($keep_empty_config) {
2394 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2399 # also remove unused disk
2401 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2404 PVE
::Storage
::foreach_volid
($dl, sub {
2405 my ($volid, $sid, $volname, $d) = @_;
2406 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2415 sub parse_vm_config
{
2416 my ($filename, $raw) = @_;
2418 return undef if !defined($raw);
2421 digest
=> Digest
::SHA
::sha1_hex
($raw),
2426 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2427 || die "got strange filename '$filename'";
2435 my @lines = split(/\n/, $raw);
2436 foreach my $line (@lines) {
2437 next if $line =~ m/^\s*$/;
2439 if ($line =~ m/^\[PENDING\]\s*$/i) {
2440 $section = 'pending';
2441 if (defined($descr)) {
2443 $conf->{description
} = $descr;
2446 $conf = $res->{$section} = {};
2449 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2451 if (defined($descr)) {
2453 $conf->{description
} = $descr;
2456 $conf = $res->{snapshots
}->{$section} = {};
2460 if ($line =~ m/^\#(.*)\s*$/) {
2461 $descr = '' if !defined($descr);
2462 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2466 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2467 $descr = '' if !defined($descr);
2468 $descr .= PVE
::Tools
::decode_text
($2);
2469 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2470 $conf->{snapstate
} = $1;
2471 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2474 $conf->{$key} = $value;
2475 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2477 if ($section eq 'pending') {
2478 $conf->{delete} = $value; # we parse this later
2480 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2482 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2485 eval { $value = check_type
($key, $value); };
2487 warn "vm $vmid - unable to parse value of '$key' - $@";
2489 $key = 'ide2' if $key eq 'cdrom';
2490 my $fmt = $confdesc->{$key}->{format
};
2491 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2492 my $v = parse_drive
($key, $value);
2493 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2494 $v->{file
} = $volid;
2495 $value = print_drive
($vmid, $v);
2497 warn "vm $vmid - unable to parse value of '$key'\n";
2502 $conf->{$key} = $value;
2507 if (defined($descr)) {
2509 $conf->{description
} = $descr;
2511 delete $res->{snapstate
}; # just to be sure
2516 sub write_vm_config
{
2517 my ($filename, $conf) = @_;
2519 delete $conf->{snapstate
}; # just to be sure
2521 if ($conf->{cdrom
}) {
2522 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2523 $conf->{ide2
} = $conf->{cdrom
};
2524 delete $conf->{cdrom
};
2527 # we do not use 'smp' any longer
2528 if ($conf->{sockets
}) {
2529 delete $conf->{smp
};
2530 } elsif ($conf->{smp
}) {
2531 $conf->{sockets
} = $conf->{smp
};
2532 delete $conf->{cores
};
2533 delete $conf->{smp
};
2536 my $used_volids = {};
2538 my $cleanup_config = sub {
2539 my ($cref, $pending, $snapname) = @_;
2541 foreach my $key (keys %$cref) {
2542 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2543 $key eq 'snapstate' || $key eq 'pending';
2544 my $value = $cref->{$key};
2545 if ($key eq 'delete') {
2546 die "propertry 'delete' is only allowed in [PENDING]\n"
2548 # fixme: check syntax?
2551 eval { $value = check_type
($key, $value); };
2552 die "unable to parse value of '$key' - $@" if $@;
2554 $cref->{$key} = $value;
2556 if (!$snapname && is_valid_drivename
($key)) {
2557 my $drive = parse_drive
($key, $value);
2558 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2563 &$cleanup_config($conf);
2565 &$cleanup_config($conf->{pending
}, 1);
2567 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2568 die "internal error" if $snapname eq 'pending';
2569 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2572 # remove 'unusedX' settings if we re-add a volume
2573 foreach my $key (keys %$conf) {
2574 my $value = $conf->{$key};
2575 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2576 delete $conf->{$key};
2580 my $generate_raw_config = sub {
2581 my ($conf, $pending) = @_;
2585 # add description as comment to top of file
2586 if (defined(my $descr = $conf->{description
})) {
2588 foreach my $cl (split(/\n/, $descr)) {
2589 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2592 $raw .= "#\n" if $pending;
2596 foreach my $key (sort keys %$conf) {
2597 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2598 $raw .= "$key: $conf->{$key}\n";
2603 my $raw = &$generate_raw_config($conf);
2605 if (scalar(keys %{$conf->{pending
}})){
2606 $raw .= "\n[PENDING]\n";
2607 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2610 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2611 $raw .= "\n[$snapname]\n";
2612 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2622 # we use static defaults from our JSON schema configuration
2623 foreach my $key (keys %$confdesc) {
2624 if (defined(my $default = $confdesc->{$key}->{default})) {
2625 $res->{$key} = $default;
2633 my $vmlist = PVE
::Cluster
::get_vmlist
();
2635 return $res if !$vmlist || !$vmlist->{ids
};
2636 my $ids = $vmlist->{ids
};
2638 foreach my $vmid (keys %$ids) {
2639 my $d = $ids->{$vmid};
2640 next if !$d->{node
} || $d->{node
} ne $nodename;
2641 next if !$d->{type
} || $d->{type
} ne 'qemu';
2642 $res->{$vmid}->{exists} = 1;
2647 # test if VM uses local resources (to prevent migration)
2648 sub check_local_resources
{
2649 my ($conf, $noerr) = @_;
2653 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2654 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2656 foreach my $k (keys %$conf) {
2657 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2658 # sockets are safe: they will recreated be on the target side post-migrate
2659 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2660 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2663 die "VM uses local resources\n" if $loc_res && !$noerr;
2668 # check if used storages are available on all nodes (use by migrate)
2669 sub check_storage_availability
{
2670 my ($storecfg, $conf, $node) = @_;
2672 foreach_drive
($conf, sub {
2673 my ($ds, $drive) = @_;
2675 my $volid = $drive->{file
};
2678 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2681 # check if storage is available on both nodes
2682 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2683 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2687 # list nodes where all VM images are available (used by has_feature API)
2689 my ($conf, $storecfg) = @_;
2691 my $nodelist = PVE
::Cluster
::get_nodelist
();
2692 my $nodehash = { map { $_ => 1 } @$nodelist };
2693 my $nodename = PVE
::INotify
::nodename
();
2695 foreach_drive
($conf, sub {
2696 my ($ds, $drive) = @_;
2698 my $volid = $drive->{file
};
2701 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2703 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2704 if ($scfg->{disable
}) {
2706 } elsif (my $avail = $scfg->{nodes
}) {
2707 foreach my $node (keys %$nodehash) {
2708 delete $nodehash->{$node} if !$avail->{$node};
2710 } elsif (!$scfg->{shared
}) {
2711 foreach my $node (keys %$nodehash) {
2712 delete $nodehash->{$node} if $node ne $nodename
2722 my ($pidfile, $pid) = @_;
2724 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2728 return undef if !$line;
2729 my @param = split(/\0/, $line);
2731 my $cmd = $param[0];
2732 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2734 for (my $i = 0; $i < scalar (@param); $i++) {
2737 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2738 my $p = $param[$i+1];
2739 return 1 if $p && ($p eq $pidfile);
2748 my ($vmid, $nocheck, $node) = @_;
2750 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2752 die "unable to find configuration file for VM $vmid - no such machine\n"
2753 if !$nocheck && ! -f
$filename;
2755 my $pidfile = pidfile_name
($vmid);
2757 if (my $fd = IO
::File-
>new("<$pidfile")) {
2762 my $mtime = $st->mtime;
2763 if ($mtime > time()) {
2764 warn "file '$filename' modified in future\n";
2767 if ($line =~ m/^(\d+)$/) {
2769 if (check_cmdline
($pidfile, $pid)) {
2770 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2782 my $vzlist = config_list
();
2784 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2786 while (defined(my $de = $fd->read)) {
2787 next if $de !~ m/^(\d+)\.pid$/;
2789 next if !defined($vzlist->{$vmid});
2790 if (my $pid = check_running
($vmid)) {
2791 $vzlist->{$vmid}->{pid
} = $pid;
2799 my ($storecfg, $conf) = @_;
2801 my $bootdisk = $conf->{bootdisk
};
2802 return undef if !$bootdisk;
2803 return undef if !is_valid_drivename
($bootdisk);
2805 return undef if !$conf->{$bootdisk};
2807 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2808 return undef if !defined($drive);
2810 return undef if drive_is_cdrom
($drive);
2812 my $volid = $drive->{file
};
2813 return undef if !$volid;
2815 return $drive->{size
};
2818 our $vmstatus_return_properties = {
2819 vmid
=> get_standard_option
('pve-vmid'),
2821 description
=> "Qemu process status.",
2823 enum
=> ['stopped', 'running'],
2826 description
=> "Maximum memory in bytes.",
2829 renderer
=> 'bytes',
2832 description
=> "Root disk size in bytes.",
2835 renderer
=> 'bytes',
2838 description
=> "VM name.",
2843 description
=> "Qemu QMP agent status.",
2848 description
=> "PID of running qemu process.",
2853 description
=> "Uptime.",
2856 renderer
=> 'duration',
2859 description
=> "Maximum usable CPUs.",
2865 my $last_proc_pid_stat;
2867 # get VM status information
2868 # This must be fast and should not block ($full == false)
2869 # We only query KVM using QMP if $full == true (this can be slow)
2871 my ($opt_vmid, $full) = @_;
2875 my $storecfg = PVE
::Storage
::config
();
2877 my $list = vzlist
();
2878 my $defaults = load_defaults
();
2880 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2882 my $cpucount = $cpuinfo->{cpus
} || 1;
2884 foreach my $vmid (keys %$list) {
2885 next if $opt_vmid && ($vmid ne $opt_vmid);
2887 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2888 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2890 my $d = { vmid
=> $vmid };
2891 $d->{pid
} = $list->{$vmid}->{pid
};
2893 # fixme: better status?
2894 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2896 my $size = disksize
($storecfg, $conf);
2897 if (defined($size)) {
2898 $d->{disk
} = 0; # no info available
2899 $d->{maxdisk
} = $size;
2905 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2906 * ($conf->{cores
} || $defaults->{cores
});
2907 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2908 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2910 $d->{name
} = $conf->{name
} || "VM $vmid";
2911 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2912 : $defaults->{memory
}*(1024*1024);
2914 if ($conf->{balloon
}) {
2915 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2916 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2917 : $defaults->{shares
};
2928 $d->{diskwrite
} = 0;
2930 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2932 $d->{serial
} = 1 if conf_has_serial
($conf);
2937 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2938 foreach my $dev (keys %$netdev) {
2939 next if $dev !~ m/^tap([1-9]\d*)i/;
2941 my $d = $res->{$vmid};
2944 $d->{netout
} += $netdev->{$dev}->{receive
};
2945 $d->{netin
} += $netdev->{$dev}->{transmit
};
2948 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2949 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2954 my $ctime = gettimeofday
;
2956 foreach my $vmid (keys %$list) {
2958 my $d = $res->{$vmid};
2959 my $pid = $d->{pid
};
2962 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2963 next if !$pstat; # not running
2965 my $used = $pstat->{utime} + $pstat->{stime
};
2967 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2969 if ($pstat->{vsize
}) {
2970 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2973 my $old = $last_proc_pid_stat->{$pid};
2975 $last_proc_pid_stat->{$pid} = {
2983 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2985 if ($dtime > 1000) {
2986 my $dutime = $used - $old->{used
};
2988 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2989 $last_proc_pid_stat->{$pid} = {
2995 $d->{cpu
} = $old->{cpu
};
2999 return $res if !$full;
3001 my $qmpclient = PVE
::QMPClient-
>new();
3003 my $ballooncb = sub {
3004 my ($vmid, $resp) = @_;
3006 my $info = $resp->{'return'};
3007 return if !$info->{max_mem
};
3009 my $d = $res->{$vmid};
3011 # use memory assigned to VM
3012 $d->{maxmem
} = $info->{max_mem
};
3013 $d->{balloon
} = $info->{actual
};
3015 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3016 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3017 $d->{freemem
} = $info->{free_mem
};
3020 $d->{ballooninfo
} = $info;
3023 my $blockstatscb = sub {
3024 my ($vmid, $resp) = @_;
3025 my $data = $resp->{'return'} || [];
3026 my $totalrdbytes = 0;
3027 my $totalwrbytes = 0;
3029 for my $blockstat (@$data) {
3030 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3031 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3033 $blockstat->{device
} =~ s/drive-//;
3034 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3036 $res->{$vmid}->{diskread
} = $totalrdbytes;
3037 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3040 my $statuscb = sub {
3041 my ($vmid, $resp) = @_;
3043 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3044 # this fails if ballon driver is not loaded, so this must be
3045 # the last commnand (following command are aborted if this fails).
3046 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3048 my $status = 'unknown';
3049 if (!defined($status = $resp->{'return'}->{status
})) {
3050 warn "unable to get VM status\n";
3054 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3057 foreach my $vmid (keys %$list) {
3058 next if $opt_vmid && ($vmid ne $opt_vmid);
3059 next if !$res->{$vmid}->{pid
}; # not running
3060 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3063 $qmpclient->queue_execute(undef, 2);
3065 foreach my $vmid (keys %$list) {
3066 next if $opt_vmid && ($vmid ne $opt_vmid);
3067 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3074 my ($conf, $func, @param) = @_;
3076 foreach my $ds (valid_drive_names
()) {
3077 next if !defined($conf->{$ds});
3079 my $drive = parse_drive
($ds, $conf->{$ds});
3082 &$func($ds, $drive, @param);
3087 my ($conf, $func, @param) = @_;
3091 my $test_volid = sub {
3092 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3096 $volhash->{$volid}->{cdrom
} //= 1;
3097 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3099 $volhash->{$volid}->{replicate
} //= 0;
3100 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3102 $volhash->{$volid}->{shared
} //= 0;
3103 $volhash->{$volid}->{shared
} = 1 if $shared;
3105 $volhash->{$volid}->{referenced_in_config
} //= 0;
3106 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3108 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3109 if defined($snapname);
3112 foreach_drive
($conf, sub {
3113 my ($ds, $drive) = @_;
3114 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3117 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3118 my $snap = $conf->{snapshots
}->{$snapname};
3119 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3120 foreach_drive
($snap, sub {
3121 my ($ds, $drive) = @_;
3122 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3126 foreach my $volid (keys %$volhash) {
3127 &$func($volid, $volhash->{$volid}, @param);
3131 sub conf_has_serial
{
3134 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3135 if ($conf->{"serial$i"}) {
3143 sub vga_conf_has_spice
{
3146 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3151 sub config_to_command
{
3152 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3155 my $globalFlags = [];
3156 my $machineFlags = [];
3162 my $kvmver = kvm_user_version
();
3163 my $vernum = 0; # unknown
3164 my $ostype = $conf->{ostype
};
3165 my $winversion = windows_version
($ostype);
3166 my $kvm = $conf->{kvm
} // 1;
3168 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3170 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3171 $vernum = $1*1000000+$2*1000;
3172 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3173 $vernum = $1*1000000+$2*1000+$3;
3176 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3178 my $have_ovz = -f
'/proc/vz/vestat';
3180 my $q35 = machine_type_is_q35
($conf);
3181 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3182 my $machine_type = $forcemachine || $conf->{machine
};
3183 my $use_old_bios_files = undef;
3184 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3186 my $cpuunits = defined($conf->{cpuunits
}) ?
3187 $conf->{cpuunits
} : $defaults->{cpuunits
};
3189 push @$cmd, '/usr/bin/kvm';
3191 push @$cmd, '-id', $vmid;
3193 my $vmname = $conf->{name
} || "vm$vmid";
3195 push @$cmd, '-name', $vmname;
3199 my $qmpsocket = qmp_socket
($vmid);
3200 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3201 push @$cmd, '-mon', "chardev=qmp,mode=control";
3204 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3206 push @$cmd, '-daemonize';
3208 if ($conf->{smbios1
}) {
3209 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3212 if ($conf->{vmgenid
}) {
3213 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3216 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3217 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3221 if (my $efidisk = $conf->{efidisk0
}) {
3222 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3223 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3224 $format = $d->{format
};
3226 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3227 if (!defined($format)) {
3228 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3229 $format = qemu_img_format
($scfg, $volname);
3233 die "efidisk format must be specified\n"
3234 if !defined($format);
3237 warn "no efidisk configured! Using temporary efivars disk.\n";
3238 $path = "/tmp/$vmid-ovmf.fd";
3239 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3243 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3244 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3248 # add usb controllers
3249 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3250 push @$devices, @usbcontrollers if @usbcontrollers;
3251 my $vga = $conf->{vga
};
3253 my $qxlnum = vga_conf_has_spice
($vga);
3254 $vga = 'qxl' if $qxlnum;
3257 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3258 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3260 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3264 # enable absolute mouse coordinates (needed by vnc)
3266 if (defined($conf->{tablet
})) {
3267 $tablet = $conf->{tablet
};
3269 $tablet = $defaults->{tablet
};
3270 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3271 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3274 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3277 my $gpu_passthrough;
3280 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3281 my $d = parse_hostpci
($conf->{"hostpci$i"});
3284 my $pcie = $d->{pcie
};
3286 die "q35 machine model is not enabled" if !$q35;
3287 $pciaddr = print_pcie_addr
("hostpci$i");
3289 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3292 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3293 my $romfile = $d->{romfile
};
3296 if ($d->{'x-vga'}) {
3297 $xvga = ',x-vga=on';
3300 $gpu_passthrough = 1;
3302 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3306 my $pcidevices = $d->{pciid
};
3307 my $multifunction = 1 if @$pcidevices > 1;
3310 foreach my $pcidevice (@$pcidevices) {
3312 my $id = "hostpci$i";
3313 $id .= ".$j" if $multifunction;
3314 my $addr = $pciaddr;
3315 $addr .= ".$j" if $multifunction;
3316 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3319 $devicestr .= "$rombar$xvga";
3320 $devicestr .= ",multifunction=on" if $multifunction;
3321 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3324 push @$devices, '-device', $devicestr;
3330 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3331 push @$devices, @usbdevices if @usbdevices;
3333 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3334 if (my $path = $conf->{"serial$i"}) {
3335 if ($path eq 'socket') {
3336 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3337 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3338 push @$devices, '-device', "isa-serial,chardev=serial$i";
3340 die "no such serial device\n" if ! -c
$path;
3341 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3342 push @$devices, '-device', "isa-serial,chardev=serial$i";
3348 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3349 if (my $path = $conf->{"parallel$i"}) {
3350 die "no such parallel device\n" if ! -c
$path;
3351 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3352 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3353 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3359 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3360 $sockets = $conf->{sockets
} if $conf->{sockets
};
3362 my $cores = $conf->{cores
} || 1;
3364 my $maxcpus = $sockets * $cores;
3366 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3368 my $allowed_vcpus = $cpuinfo->{cpus
};
3370 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3371 if ($allowed_vcpus < $maxcpus);
3373 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3375 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3376 for (my $i = 2; $i <= $vcpus; $i++) {
3377 my $cpustr = print_cpu_device
($conf,$i);
3378 push @$cmd, '-device', $cpustr;
3383 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3385 push @$cmd, '-nodefaults';
3387 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3389 my $bootindex_hash = {};
3391 foreach my $o (split(//, $bootorder)) {
3392 $bootindex_hash->{$o} = $i*100;
3396 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3398 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3400 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3402 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3404 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3405 my $socket = vnc_socket
($vmid);
3406 push @$cmd, '-vnc', "unix:$socket,x509,password";
3408 push @$cmd, '-nographic';
3412 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3414 my $useLocaltime = $conf->{localtime};
3416 if ($winversion >= 5) { # windows
3417 $useLocaltime = 1 if !defined($conf->{localtime});
3419 # use time drift fix when acpi is enabled
3420 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3421 $tdf = 1 if !defined($conf->{tdf
});
3425 if ($winversion >= 6) {
3426 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3427 push @$cmd, '-no-hpet';
3430 push @$rtcFlags, 'driftfix=slew' if $tdf;
3433 push @$machineFlags, 'accel=tcg';
3436 if ($machine_type) {
3437 push @$machineFlags, "type=${machine_type}";
3440 if ($conf->{startdate
}) {
3441 push @$rtcFlags, "base=$conf->{startdate}";
3442 } elsif ($useLocaltime) {
3443 push @$rtcFlags, 'base=localtime';
3446 my $cpu = $kvm ?
"kvm64" : "qemu64";
3447 if (my $cputype = $conf->{cpu
}) {
3448 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3449 or die "Cannot parse cpu description: $cputype\n";
3450 $cpu = $cpuconf->{cputype
};
3451 $kvm_off = 1 if $cpuconf->{hidden
};
3453 if (defined(my $flags = $cpuconf->{flags
})) {
3454 push @$cpuFlags, split(";", $flags);
3458 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3460 push @$cpuFlags , '-x2apic'
3461 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3463 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3465 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3467 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3469 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3470 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3473 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3475 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3477 push @$cpuFlags, 'kvm=off' if $kvm_off;
3479 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3480 die "internal error"; # should not happen
3482 push @$cpuFlags, "vendor=${cpu_vendor}"
3483 if $cpu_vendor ne 'default';
3485 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3487 push @$cmd, '-cpu', $cpu;
3489 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3491 push @$cmd, '-S' if $conf->{freeze
};
3493 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3496 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3497 #push @$cmd, '-soundhw', 'es1370';
3498 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3500 if (parse_guest_agent
($conf)->{enabled
}) {
3501 my $qgasocket = qmp_socket
($vmid, 1);
3502 my $pciaddr = print_pci_addr
("qga0", $bridges);
3503 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3504 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3505 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3513 for(my $i = 1; $i < $qxlnum; $i++){
3514 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3515 push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3518 # assume other OS works like Linux
3519 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3520 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3524 my $pciaddr = print_pci_addr
("spice", $bridges);
3526 my $nodename = PVE
::INotify
::nodename
();
3527 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3528 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3529 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3530 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3531 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3533 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3535 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3536 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3537 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3540 # enable balloon by default, unless explicitly disabled
3541 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3542 $pciaddr = print_pci_addr
("balloon0", $bridges);
3543 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3546 if ($conf->{watchdog
}) {
3547 my $wdopts = parse_watchdog
($conf->{watchdog
});
3548 $pciaddr = print_pci_addr
("watchdog", $bridges);
3549 my $watchdog = $wdopts->{model
} || 'i6300esb';
3550 push @$devices, '-device', "$watchdog$pciaddr";
3551 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3555 my $scsicontroller = {};
3556 my $ahcicontroller = {};
3557 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3559 # Add iscsi initiator name if available
3560 if (my $initiator = get_initiator_name
()) {
3561 push @$devices, '-iscsi', "initiator-name=$initiator";
3564 foreach_drive
($conf, sub {
3565 my ($ds, $drive) = @_;
3567 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3568 push @$vollist, $drive->{file
};
3571 # ignore efidisk here, already added in bios/fw handling code above
3572 return if $drive->{interface
} eq 'efidisk';
3574 $use_virtio = 1 if $ds =~ m/^virtio/;
3576 if (drive_is_cdrom
($drive)) {
3577 if ($bootindex_hash->{d
}) {
3578 $drive->{bootindex
} = $bootindex_hash->{d
};
3579 $bootindex_hash->{d
} += 1;
3582 if ($bootindex_hash->{c
}) {
3583 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3584 $bootindex_hash->{c
} += 1;
3588 if($drive->{interface
} eq 'virtio'){
3589 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3592 if ($drive->{interface
} eq 'scsi') {
3594 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3596 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3597 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3600 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3601 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3602 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3603 } elsif ($drive->{iothread
}) {
3604 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3608 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3609 $queues = ",num_queues=$drive->{queues}";
3612 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3613 $scsicontroller->{$controller}=1;
3616 if ($drive->{interface
} eq 'sata') {
3617 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3618 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3619 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3620 $ahcicontroller->{$controller}=1;
3623 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3624 push @$devices, '-drive',$drive_cmd;
3625 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3628 for (my $i = 0; $i < $MAX_NETS; $i++) {
3629 next if !$conf->{"net$i"};
3630 my $d = parse_net
($conf->{"net$i"});
3633 $use_virtio = 1 if $d->{model
} eq 'virtio';
3635 if ($bootindex_hash->{n
}) {
3636 $d->{bootindex
} = $bootindex_hash->{n
};
3637 $bootindex_hash->{n
} += 1;
3640 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3641 push @$devices, '-netdev', $netdevfull;
3643 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3644 push @$devices, '-device', $netdevicefull;
3649 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3654 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3656 while (my ($k, $v) = each %$bridges) {
3657 $pciaddr = print_pci_addr
("pci.$k");
3658 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3663 if ($conf->{args
}) {
3664 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3668 push @$cmd, @$devices;
3669 push @$cmd, '-rtc', join(',', @$rtcFlags)
3670 if scalar(@$rtcFlags);
3671 push @$cmd, '-machine', join(',', @$machineFlags)
3672 if scalar(@$machineFlags);
3673 push @$cmd, '-global', join(',', @$globalFlags)
3674 if scalar(@$globalFlags);
3676 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3681 return "${var_run_tmpdir}/$vmid.vnc";
3687 my $res = vm_mon_cmd
($vmid, 'query-spice');
3689 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3693 my ($vmid, $qga) = @_;
3694 my $sockettype = $qga ?
'qga' : 'qmp';
3695 return "${var_run_tmpdir}/$vmid.$sockettype";
3700 return "${var_run_tmpdir}/$vmid.pid";
3703 sub vm_devices_list
{
3706 my $res = vm_mon_cmd
($vmid, 'query-pci');
3707 my $devices_to_check = [];
3709 foreach my $pcibus (@$res) {
3710 push @$devices_to_check, @{$pcibus->{devices
}},
3713 while (@$devices_to_check) {
3715 for my $d (@$devices_to_check) {
3716 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3717 next if !$d->{'pci_bridge'};
3719 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3720 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3722 $devices_to_check = $to_check;
3725 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3726 foreach my $block (@$resblock) {
3727 if($block->{device
} =~ m/^drive-(\S+)/){
3732 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3733 foreach my $mice (@$resmice) {
3734 if ($mice->{name
} eq 'QEMU HID Tablet') {
3735 $devices->{tablet
} = 1;
3740 # for usb devices there is no query-usb
3741 # but we can iterate over the entries in
3742 # qom-list path=/machine/peripheral
3743 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3744 foreach my $per (@$resperipheral) {
3745 if ($per->{name
} =~ m/^usb\d+$/) {
3746 $devices->{$per->{name
}} = 1;
3754 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3756 my $q35 = machine_type_is_q35
($conf);
3758 my $devices_list = vm_devices_list
($vmid);
3759 return 1 if defined($devices_list->{$deviceid});
3761 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3763 if ($deviceid eq 'tablet') {
3765 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3767 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3769 die "usb hotplug currently not reliable\n";
3770 # since we can't reliably hot unplug all added usb devices
3771 # and usb passthrough disables live migration
3772 # we disable usb hotplugging for now
3773 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3775 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3777 qemu_iothread_add
($vmid, $deviceid, $device);
3779 qemu_driveadd
($storecfg, $vmid, $device);
3780 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3782 qemu_deviceadd
($vmid, $devicefull);
3783 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3785 eval { qemu_drivedel
($vmid, $deviceid); };
3790 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3793 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3794 my $pciaddr = print_pci_addr
($deviceid);
3795 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3797 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3799 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3800 qemu_iothread_add
($vmid, $deviceid, $device);
3801 $devicefull .= ",iothread=iothread-$deviceid";
3804 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3805 $devicefull .= ",num_queues=$device->{queues}";
3808 qemu_deviceadd
($vmid, $devicefull);
3809 qemu_deviceaddverify
($vmid, $deviceid);
3811 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3813 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3814 qemu_driveadd
($storecfg, $vmid, $device);
3816 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3817 eval { qemu_deviceadd
($vmid, $devicefull); };
3819 eval { qemu_drivedel
($vmid, $deviceid); };
3824 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3826 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3828 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3829 my $use_old_bios_files = undef;
3830 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3832 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3833 qemu_deviceadd
($vmid, $netdevicefull);
3834 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3836 eval { qemu_netdevdel
($vmid, $deviceid); };
3841 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3844 my $pciaddr = print_pci_addr
($deviceid);
3845 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3847 qemu_deviceadd
($vmid, $devicefull);
3848 qemu_deviceaddverify
($vmid, $deviceid);
3851 die "can't hotplug device '$deviceid'\n";
3857 # fixme: this should raise exceptions on error!
3858 sub vm_deviceunplug
{
3859 my ($vmid, $conf, $deviceid) = @_;
3861 my $devices_list = vm_devices_list
($vmid);
3862 return 1 if !defined($devices_list->{$deviceid});
3864 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3866 if ($deviceid eq 'tablet') {
3868 qemu_devicedel
($vmid, $deviceid);
3870 } elsif ($deviceid =~ m/^usb\d+$/) {
3872 die "usb hotplug currently not reliable\n";
3873 # when unplugging usb devices this way,
3874 # there may be remaining usb controllers/hubs
3875 # so we disable it for now
3876 qemu_devicedel
($vmid, $deviceid);
3877 qemu_devicedelverify
($vmid, $deviceid);
3879 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3881 qemu_devicedel
($vmid, $deviceid);
3882 qemu_devicedelverify
($vmid, $deviceid);
3883 qemu_drivedel
($vmid, $deviceid);
3884 qemu_iothread_del
($conf, $vmid, $deviceid);
3886 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3888 qemu_devicedel
($vmid, $deviceid);
3889 qemu_devicedelverify
($vmid, $deviceid);
3890 qemu_iothread_del
($conf, $vmid, $deviceid);
3892 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3894 qemu_devicedel
($vmid, $deviceid);
3895 qemu_drivedel
($vmid, $deviceid);
3896 qemu_deletescsihw
($conf, $vmid, $deviceid);
3898 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3900 qemu_devicedel
($vmid, $deviceid);
3901 qemu_devicedelverify
($vmid, $deviceid);
3902 qemu_netdevdel
($vmid, $deviceid);
3905 die "can't unplug device '$deviceid'\n";
3911 sub qemu_deviceadd
{
3912 my ($vmid, $devicefull) = @_;
3914 $devicefull = "driver=".$devicefull;
3915 my %options = split(/[=,]/, $devicefull);
3917 vm_mon_cmd
($vmid, "device_add" , %options);
3920 sub qemu_devicedel
{
3921 my ($vmid, $deviceid) = @_;
3923 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3926 sub qemu_iothread_add
{
3927 my($vmid, $deviceid, $device) = @_;
3929 if ($device->{iothread
}) {
3930 my $iothreads = vm_iothreads_list
($vmid);
3931 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3935 sub qemu_iothread_del
{
3936 my($conf, $vmid, $deviceid) = @_;
3938 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3939 if ($device->{iothread
}) {
3940 my $iothreads = vm_iothreads_list
($vmid);
3941 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3945 sub qemu_objectadd
{
3946 my($vmid, $objectid, $qomtype) = @_;
3948 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3953 sub qemu_objectdel
{
3954 my($vmid, $objectid) = @_;
3956 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3962 my ($storecfg, $vmid, $device) = @_;
3964 my $drive = print_drive_full
($storecfg, $vmid, $device);
3965 $drive =~ s/\\/\\\\/g;
3966 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3968 # If the command succeeds qemu prints: "OK
"
3969 return 1 if $ret =~ m/OK/s;
3971 die "adding drive failed
: $ret\n";
3975 my($vmid, $deviceid) = @_;
3977 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3980 return 1 if $ret eq "";
3982 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3983 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3985 die "deleting drive
$deviceid failed
: $ret\n";
3988 sub qemu_deviceaddverify {
3989 my ($vmid, $deviceid) = @_;
3991 for (my $i = 0; $i <= 5; $i++) {
3992 my $devices_list = vm_devices_list($vmid);
3993 return 1 if defined($devices_list->{$deviceid});
3997 die "error on hotplug device
'$deviceid'\n";
4001 sub qemu_devicedelverify {
4002 my ($vmid, $deviceid) = @_;
4004 # need to verify that the device is correctly removed as device_del
4005 # is async and empty return is not reliable
4007 for (my $i = 0; $i <= 5; $i++) {
4008 my $devices_list = vm_devices_list($vmid);
4009 return 1 if !defined($devices_list->{$deviceid});
4013 die "error on hot-unplugging device
'$deviceid'\n";
4016 sub qemu_findorcreatescsihw {
4017 my ($storecfg, $conf, $vmid, $device) = @_;
4019 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4021 my $scsihwid="$controller_prefix$controller";
4022 my $devices_list = vm_devices_list($vmid);
4024 if(!defined($devices_list->{$scsihwid})) {
4025 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
4031 sub qemu_deletescsihw {
4032 my ($conf, $vmid, $opt) = @_;
4034 my $device = parse_drive($opt, $conf->{$opt});
4036 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4037 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4041 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4043 my $devices_list = vm_devices_list($vmid);
4044 foreach my $opt (keys %{$devices_list}) {
4045 if (PVE::QemuServer::is_valid_drivename($opt)) {
4046 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4047 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4053 my $scsihwid="scsihw
$controller";
4055 vm_deviceunplug($vmid, $conf, $scsihwid);
4060 sub qemu_add_pci_bridge {
4061 my ($storecfg, $conf, $vmid, $device) = @_;
4067 print_pci_addr($device, $bridges);
4069 while (my ($k, $v) = each %$bridges) {
4072 return 1 if !defined($bridgeid) || $bridgeid < 1;
4074 my $bridge = "pci
.$bridgeid";
4075 my $devices_list = vm_devices_list($vmid);
4077 if (!defined($devices_list->{$bridge})) {
4078 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
4084 sub qemu_set_link_status {
4085 my ($vmid, $device, $up) = @_;
4087 vm_mon_cmd($vmid, "set_link
", name => $device,
4088 up => $up ? JSON::true : JSON::false);
4091 sub qemu_netdevadd {
4092 my ($vmid, $conf, $device, $deviceid) = @_;
4094 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
4095 my %options = split(/[=,]/, $netdev);
4097 vm_mon_cmd($vmid, "netdev_add
", %options);
4101 sub qemu_netdevdel {
4102 my ($vmid, $deviceid) = @_;
4104 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4107 sub qemu_usb_hotplug {
4108 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4112 # remove the old one first
4113 vm_deviceunplug($vmid, $conf, $deviceid);
4115 # check if xhci controller is necessary and available
4116 if ($device->{usb3}) {
4118 my $devicelist = vm_devices_list($vmid);
4120 if (!$devicelist->{xhci}) {
4121 my $pciaddr = print_pci_addr("xhci
");
4122 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4125 my $d = parse_usb_device($device->{host});
4126 $d->{usb3} = $device->{usb3};
4129 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4132 sub qemu_cpu_hotplug {
4133 my ($vmid, $conf, $vcpus) = @_;
4135 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4138 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4139 $sockets = $conf->{sockets} if $conf->{sockets};
4140 my $cores = $conf->{cores} || 1;
4141 my $maxcpus = $sockets * $cores;
4143 $vcpus = $maxcpus if !$vcpus;
4145 die "you can
't add more vcpus than maxcpus\n"
4146 if $vcpus > $maxcpus;
4148 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4150 if ($vcpus < $currentvcpus) {
4152 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4154 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4155 qemu_devicedel($vmid, "cpu$i");
4157 my $currentrunningvcpus = undef;
4159 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4160 last if scalar(@{$currentrunningvcpus}) == $i-1;
4161 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4165 #update conf after each succesfull cpu unplug
4166 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4167 PVE::QemuConfig->write_config($vmid, $conf);
4170 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4176 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4177 die "vcpus in running vm does not match its configuration\n"
4178 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4180 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4182 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4183 my $cpustr = print_cpu_device($conf, $i);
4184 qemu_deviceadd($vmid, $cpustr);
4187 my $currentrunningvcpus = undef;
4189 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4190 last if scalar(@{$currentrunningvcpus}) == $i;
4191 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4195 #update conf after each succesfull cpu hotplug
4196 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4197 PVE::QemuConfig->write_config($vmid, $conf);
4201 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4202 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4207 sub qemu_block_set_io_throttle {
4208 my ($vmid, $deviceid,
4209 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4210 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4211 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4212 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4214 return if !check_running($vmid) ;
4216 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4218 bps_rd => int($bps_rd),
4219 bps_wr => int($bps_wr),
4221 iops_rd => int($iops_rd),
4222 iops_wr => int($iops_wr),
4223 bps_max => int($bps_max),
4224 bps_rd_max => int($bps_rd_max),
4225 bps_wr_max => int($bps_wr_max),
4226 iops_max => int($iops_max),
4227 iops_rd_max => int($iops_rd_max),
4228 iops_wr_max => int($iops_wr_max),
4229 bps_max_length => int($bps_max_length),
4230 bps_rd_max_length => int($bps_rd_max_length),
4231 bps_wr_max_length => int($bps_wr_max_length),
4232 iops_max_length => int($iops_max_length),
4233 iops_rd_max_length => int($iops_rd_max_length),
4234 iops_wr_max_length => int($iops_wr_max_length),
4239 # old code, only used to shutdown old VM after update
4241 my ($fh, $timeout) = @_;
4243 my $sel = new IO::Select;
4250 while (scalar (@ready = $sel->can_read($timeout))) {
4252 if ($count = $fh->sysread($buf, 8192)) {
4253 if ($buf =~ /^(.*)\(qemu\) $/s) {
4260 if (!defined($count)) {
4267 die "monitor read timeout\n" if !scalar(@ready);
4272 sub qemu_block_resize {
4273 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4275 my $running = check_running($vmid);
4277 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4279 return if !$running;
4281 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4285 sub qemu_volume_snapshot {
4286 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4288 my $running = check_running($vmid);
4290 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4291 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4293 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4297 sub qemu_volume_snapshot_delete {
4298 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4300 my $running = check_running($vmid);
4305 my $conf = PVE::QemuConfig->load_config($vmid);
4306 foreach_drive($conf, sub {
4307 my ($ds, $drive) = @_;
4308 $running = 1 if $drive->{file} eq $volid;
4312 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4313 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4315 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4319 sub set_migration_caps {
4325 "auto-converge" => 1,
4327 "x-rdma-pin-all" => 0,
4332 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4334 for my $supported_capability (@$supported_capabilities) {
4336 capability => $supported_capability->{capability},
4337 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4341 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4344 my $fast_plug_option = {
4352 'vmstatestorage
' => 1,
4355 # hotplug changes in [PENDING]
4356 # $selection hash can be used to only apply specified options, for
4357 # example: { cores => 1 } (only apply changed 'cores
')
4358 # $errors ref is used to return error messages
4359 sub vmconfig_hotplug_pending {
4360 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4362 my $defaults = load_defaults();
4364 # commit values which do not have any impact on running VM first
4365 # Note: those option cannot raise errors, we we do not care about
4366 # $selection and always apply them.
4368 my $add_error = sub {
4369 my ($opt, $msg) = @_;
4370 $errors->{$opt} = "hotplug problem - $msg";
4374 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4375 if ($fast_plug_option->{$opt}) {
4376 $conf->{$opt} = $conf->{pending}->{$opt};
4377 delete $conf->{pending}->{$opt};
4383 PVE::QemuConfig->write_config($vmid, $conf);
4384 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4387 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4389 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4390 while (my ($opt, $force) = each %$pending_delete_hash) {
4391 next if $selection && !$selection->{$opt};
4393 if ($opt eq 'hotplug
') {
4394 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4395 } elsif ($opt eq 'tablet
') {
4396 die "skip\n" if !$hotplug_features->{usb};
4397 if ($defaults->{tablet}) {
4398 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4400 vm_deviceunplug($vmid, $conf, $opt);
4402 } elsif ($opt =~ m/^usb\d+/) {
4404 # since we cannot reliably hot unplug usb devices
4405 # we are disabling it
4406 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4407 vm_deviceunplug($vmid, $conf, $opt);
4408 } elsif ($opt eq 'vcpus
') {
4409 die "skip\n" if !$hotplug_features->{cpu};
4410 qemu_cpu_hotplug($vmid, $conf, undef);
4411 } elsif ($opt eq 'balloon
') {
4412 # enable balloon device is not hotpluggable
4413 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4414 # here we reset the ballooning value to memory
4415 my $balloon = $conf->{memory} || $defaults->{memory};
4416 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4417 } elsif ($fast_plug_option->{$opt}) {
4419 } elsif ($opt =~ m/^net(\d+)$/) {
4420 die "skip\n" if !$hotplug_features->{network};
4421 vm_deviceunplug($vmid, $conf, $opt);
4422 } elsif (is_valid_drivename($opt)) {
4423 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4424 vm_deviceunplug($vmid, $conf, $opt);
4425 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4426 } elsif ($opt =~ m/^memory$/) {
4427 die "skip\n" if !$hotplug_features->{memory};
4428 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4429 } elsif ($opt eq 'cpuunits
') {
4430 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4431 } elsif ($opt eq 'cpulimit
') {
4432 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4438 &$add_error($opt, $err) if $err ne "skip\n";
4440 # save new config if hotplug was successful
4441 delete $conf->{$opt};
4442 vmconfig_undelete_pending_option($conf, $opt);
4443 PVE::QemuConfig->write_config($vmid, $conf);
4444 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4448 my $apply_pending_cloudinit;
4449 $apply_pending_cloudinit = sub {
4450 my ($key, $value) = @_;
4451 $apply_pending_cloudinit = sub {}; # once is enough
4453 my @cloudinit_opts = keys %$confdesc_cloudinit;
4454 foreach my $opt (keys %{$conf->{pending}}) {
4455 next if !grep { $_ eq $opt } @cloudinit_opts;
4456 $conf->{$opt} = delete $conf->{pending}->{$opt};
4459 my $new_conf = { %$conf };
4460 $new_conf->{$key} = $value;
4461 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4464 foreach my $opt (keys %{$conf->{pending}}) {
4465 next if $selection && !$selection->{$opt};
4466 my $value = $conf->{pending}->{$opt};
4468 if ($opt eq 'hotplug
') {
4469 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4470 } elsif ($opt eq 'tablet
') {
4471 die "skip\n" if !$hotplug_features->{usb};
4473 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4474 } elsif ($value == 0) {
4475 vm_deviceunplug($vmid, $conf, $opt);
4477 } elsif ($opt =~ m/^usb\d+$/) {
4479 # since we cannot reliably hot unplug usb devices
4480 # we are disabling it
4481 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4482 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4483 die "skip\n" if !$d;
4484 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4485 } elsif ($opt eq 'vcpus
') {
4486 die "skip\n" if !$hotplug_features->{cpu};
4487 qemu_cpu_hotplug($vmid, $conf, $value);
4488 } elsif ($opt eq 'balloon
') {
4489 # enable/disable balloning device is not hotpluggable
4490 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4491 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4492 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4494 # allow manual ballooning if shares is set to zero
4495 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4496 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4497 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4499 } elsif ($opt =~ m/^net(\d+)$/) {
4500 # some changes can be done without hotplug
4501 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4502 $vmid, $opt, $value);
4503 } elsif (is_valid_drivename($opt)) {
4504 # some changes can be done without hotplug
4505 my $drive = parse_drive($opt, $value);
4506 if (drive_is_cloudinit($drive)) {
4507 &$apply_pending_cloudinit($opt, $value);
4509 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4510 $vmid, $opt, $value, 1);
4511 } elsif ($opt =~ m/^memory$/) { #dimms
4512 die "skip\n" if !$hotplug_features->{memory};
4513 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4514 } elsif ($opt eq 'cpuunits
') {
4515 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4516 } elsif ($opt eq 'cpulimit
') {
4517 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4518 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4520 die "skip\n"; # skip non-hot-pluggable options
4524 &$add_error($opt, $err) if $err ne "skip\n";
4526 # save new config if hotplug was successful
4527 $conf->{$opt} = $value;
4528 delete $conf->{pending}->{$opt};
4529 PVE::QemuConfig->write_config($vmid, $conf);
4530 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4535 sub try_deallocate_drive {
4536 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4538 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4539 my $volid = $drive->{file};
4540 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4541 my $sid = PVE::Storage::parse_volume_id($volid);
4542 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4544 # check if the disk is really unused
4545 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4546 if is_volume_in_use($storecfg, $conf, $key, $volid);
4547 PVE::Storage::vdisk_free($storecfg, $volid);
4550 # If vm is not owner of this disk remove from config
4558 sub vmconfig_delete_or_detach_drive {
4559 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4561 my $drive = parse_drive($opt, $conf->{$opt});
4563 my $rpcenv = PVE::RPCEnvironment::get();
4564 my $authuser = $rpcenv->get_user();
4567 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4568 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4570 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4574 sub vmconfig_apply_pending {
4575 my ($vmid, $conf, $storecfg) = @_;
4579 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4580 while (my ($opt, $force) = each %$pending_delete_hash) {
4581 die "internal error" if $opt =~ m/^unused/;
4582 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4583 if (!defined($conf->{$opt})) {
4584 vmconfig_undelete_pending_option($conf, $opt);
4585 PVE::QemuConfig->write_config($vmid, $conf);
4586 } elsif (is_valid_drivename($opt)) {
4587 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4588 vmconfig_undelete_pending_option($conf, $opt);
4589 delete $conf->{$opt};
4590 PVE::QemuConfig->write_config($vmid, $conf);
4592 vmconfig_undelete_pending_option($conf, $opt);
4593 delete $conf->{$opt};
4594 PVE::QemuConfig->write_config($vmid, $conf);
4598 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4600 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4601 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4603 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4604 # skip if nothing changed
4605 } elsif (is_valid_drivename($opt)) {
4606 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4607 if defined($conf->{$opt});
4608 $conf->{$opt} = $conf->{pending}->{$opt};
4610 $conf->{$opt} = $conf->{pending}->{$opt};
4613 delete $conf->{pending}->{$opt};
4614 PVE::QemuConfig->write_config($vmid, $conf);
4618 my $safe_num_ne = sub {
4621 return 0 if !defined($a) && !defined($b);
4622 return 1 if !defined($a);
4623 return 1 if !defined($b);
4628 my $safe_string_ne = sub {
4631 return 0 if !defined($a) && !defined($b);
4632 return 1 if !defined($a);
4633 return 1 if !defined($b);
4638 sub vmconfig_update_net {
4639 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4641 my $newnet = parse_net($value);
4643 if ($conf->{$opt}) {
4644 my $oldnet = parse_net($conf->{$opt});
4646 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4647 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4648 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4649 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4651 # for non online change, we try to hot-unplug
4652 die "skip\n" if !$hotplug;
4653 vm_deviceunplug($vmid, $conf, $opt);
4656 die "internal error" if $opt !~ m/net(\d+)/;
4657 my $iface = "tap${vmid}i$1";
4659 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4660 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4661 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4662 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4663 PVE::Network::tap_unplug($iface);
4664 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4665 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4666 # Rate can be applied on its own but any change above needs to
4667 # include the rate in tap_plug since OVS resets everything.
4668 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4671 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4672 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4680 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4686 sub vmconfig_update_disk {
4687 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4689 # fixme: do we need force?
4691 my $drive = parse_drive($opt, $value);
4693 if ($conf->{$opt}) {
4695 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4697 my $media = $drive->{media} || 'disk
';
4698 my $oldmedia = $old_drive->{media} || 'disk
';
4699 die "unable to change media type\n" if $media ne $oldmedia;
4701 if (!drive_is_cdrom($old_drive)) {
4703 if ($drive->{file} ne $old_drive->{file}) {
4705 die "skip\n" if !$hotplug;
4707 # unplug and register as unused
4708 vm_deviceunplug($vmid, $conf, $opt);
4709 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4712 # update existing disk
4714 # skip non hotpluggable value
4715 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4716 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4717 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4718 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4723 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4724 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4725 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4726 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4727 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4728 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4729 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4730 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4731 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4732 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4733 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4734 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4735 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4736 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4737 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4738 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4739 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4740 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4742 qemu_block_set_io_throttle($vmid,"drive-$opt",
4743 ($drive->{mbps} || 0)*1024*1024,
4744 ($drive->{mbps_rd} || 0)*1024*1024,
4745 ($drive->{mbps_wr} || 0)*1024*1024,
4746 $drive->{iops} || 0,
4747 $drive->{iops_rd} || 0,
4748 $drive->{iops_wr} || 0,
4749 ($drive->{mbps_max} || 0)*1024*1024,
4750 ($drive->{mbps_rd_max} || 0)*1024*1024,
4751 ($drive->{mbps_wr_max} || 0)*1024*1024,
4752 $drive->{iops_max} || 0,
4753 $drive->{iops_rd_max} || 0,
4754 $drive->{iops_wr_max} || 0,
4755 $drive->{bps_max_length} || 1,
4756 $drive->{bps_rd_max_length} || 1,
4757 $drive->{bps_wr_max_length} || 1,
4758 $drive->{iops_max_length} || 1,
4759 $drive->{iops_rd_max_length} || 1,
4760 $drive->{iops_wr_max_length} || 1);
4769 if ($drive->{file} eq 'none
') {
4770 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4771 if (drive_is_cloudinit($old_drive)) {
4772 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4775 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4776 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4777 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4785 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4787 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4788 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4792 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4793 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4795 PVE::QemuConfig->lock_config($vmid, sub {
4796 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4798 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4800 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4802 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4804 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4805 vmconfig_apply_pending($vmid, $conf, $storecfg);
4806 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4809 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4811 my $defaults = load_defaults();
4813 # set environment variable useful inside network script
4814 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4816 my $local_volumes = {};
4818 if ($targetstorage) {
4819 foreach_drive($conf, sub {
4820 my ($ds, $drive) = @_;
4822 return if drive_is_cdrom($drive);
4824 my $volid = $drive->{file};
4828 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4830 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4831 return if $scfg->{shared};
4832 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4837 foreach my $opt (sort keys %$local_volumes) {
4839 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4840 my $drive = parse_drive($opt, $conf->{$opt});
4842 #if remote storage is specified, use default format
4843 if ($targetstorage && $targetstorage ne "1") {
4844 $storeid = $targetstorage;
4845 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4846 $format = $defFormat;
4848 #else we use same format than original
4849 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4850 $format = qemu_img_format($scfg, $volid);
4853 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4854 my $newdrive = $drive;
4855 $newdrive->{format} = $format;
4856 $newdrive->{file} = $newvolid;
4857 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4858 $local_volumes->{$opt} = $drivestr;
4859 #pass drive to conf for command line
4860 $conf->{$opt} = $drivestr;
4864 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4866 my $migrate_port = 0;
4869 if ($statefile eq 'tcp
') {
4870 my $localip = "localhost";
4871 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4872 my $nodename = PVE::INotify::nodename();
4874 if (!defined($migration_type)) {
4875 if (defined($datacenterconf->{migration}->{type})) {
4876 $migration_type = $datacenterconf->{migration}->{type};
4878 $migration_type = 'secure
';
4882 if ($migration_type eq 'insecure
') {
4883 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4884 if ($migrate_network_addr) {
4885 $localip = $migrate_network_addr;
4887 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4890 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4893 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4894 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4895 $migrate_uri = "tcp:${localip}:${migrate_port}";
4896 push @$cmd, '-incoming
', $migrate_uri;
4899 } elsif ($statefile eq 'unix
') {
4900 # should be default for secure migrations as a ssh TCP forward
4901 # tunnel is not deterministic reliable ready and fails regurarly
4902 # to set up in time, so use UNIX socket forwards
4903 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4904 unlink $socket_addr;
4906 $migrate_uri = "unix:$socket_addr";
4908 push @$cmd, '-incoming
', $migrate_uri;
4912 push @$cmd, '-loadstate
', $statefile;
4919 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4920 my $d = parse_hostpci($conf->{"hostpci$i"});
4922 my $pcidevices = $d->{pciid};
4923 foreach my $pcidevice (@$pcidevices) {
4924 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4926 my $info = pci_device_info("0000:$pciid");
4927 die "IOMMU not present\n" if !check_iommu_support();
4928 die "no pci device info for device '$pciid'\n" if !$info;
4929 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4930 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4934 PVE::Storage::activate_volumes($storecfg, $vollist);
4936 if (!check_running($vmid, 1)) {
4938 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4939 outfunc => sub {}, errfunc => sub {});
4943 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4944 : $defaults->{cpuunits};
4946 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4947 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4950 Slice => 'qemu
.slice
',
4952 CPUShares => $cpuunits
4955 if (my $cpulimit = $conf->{cpulimit}) {
4956 $properties{CPUQuota} = int($cpulimit * 100);
4958 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4960 my $run_qemu = sub {
4961 PVE::Tools::run_fork sub {
4962 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4963 run_command($cmd, %run_params);
4967 if ($conf->{hugepages}) {
4970 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4971 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4973 PVE::QemuServer::Memory::hugepages_mount();
4974 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4976 eval { $run_qemu->() };
4978 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4982 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4984 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4987 eval { $run_qemu->() };
4991 # deactivate volumes if start fails
4992 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4993 die "start failed: $err";
4996 print "migration listens on $migrate_uri\n" if $migrate_uri;
4998 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4999 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5003 #start nbd server for storage migration
5004 if ($targetstorage) {
5005 my $nodename = PVE::INotify::nodename();
5006 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5007 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5008 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5009 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5011 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5013 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5015 foreach my $opt (sort keys %$local_volumes) {
5016 my $volid = $local_volumes->{$opt};
5017 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5018 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5019 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5023 if ($migratedfrom) {
5025 set_migration_caps($vmid);
5030 print "spice listens on port $spice_port\n";
5031 if ($spice_ticket) {
5032 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5033 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5038 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5039 if !$statefile && $conf->{balloon};
5041 foreach my $opt (keys %$conf) {
5042 next if $opt !~ m/^net\d+$/;
5043 my $nicconf = parse_net($conf->{$opt});
5044 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5048 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5049 path => "machine/peripheral/balloon0",
5050 property => "guest-stats-polling-interval",
5051 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5057 my ($vmid, $execute, %params) = @_;
5059 my $cmd = { execute => $execute, arguments => \%params };
5060 vm_qmp_command($vmid, $cmd);
5063 sub vm_mon_cmd_nocheck {
5064 my ($vmid, $execute, %params) = @_;
5066 my $cmd = { execute => $execute, arguments => \%params };
5067 vm_qmp_command($vmid, $cmd, 1);
5070 sub vm_qmp_command {
5071 my ($vmid, $cmd, $nocheck) = @_;
5076 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5077 $timeout = $cmd->{arguments}->{timeout};
5078 delete $cmd->{arguments}->{timeout};
5082 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5083 my $sname = qmp_socket($vmid);
5084 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5085 my $qmpclient = PVE::QMPClient->new();
5087 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5089 die "unable to open monitor socket\n";
5093 syslog("err", "VM $vmid qmp command failed - $err");
5100 sub vm_human_monitor_command {
5101 my ($vmid, $cmdline) = @_;
5106 execute => 'human-monitor-command
',
5107 arguments => { 'command-line
' => $cmdline},
5110 return vm_qmp_command($vmid, $cmd);
5113 sub vm_commandline {
5114 my ($storecfg, $vmid) = @_;
5116 my $conf = PVE::QemuConfig->load_config($vmid);
5118 my $defaults = load_defaults();
5120 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5122 return PVE::Tools::cmd2string($cmd);
5126 my ($vmid, $skiplock) = @_;
5128 PVE::QemuConfig->lock_config($vmid, sub {
5130 my $conf = PVE::QemuConfig->load_config($vmid);
5132 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5134 vm_mon_cmd($vmid, "system_reset");
5138 sub get_vm_volumes {
5142 foreach_volid($conf, sub {
5143 my ($volid, $attr) = @_;
5145 return if $volid =~ m|^/|;
5147 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5150 push @$vollist, $volid;
5156 sub vm_stop_cleanup {
5157 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5162 my $vollist = get_vm_volumes($conf);
5163 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5166 foreach my $ext (qw(mon qmp pid vnc qga)) {
5167 unlink "/var/run/qemu-server/${vmid}.$ext";
5170 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5172 warn $@ if $@; # avoid errors - just warn
5175 # Note: use $nockeck to skip tests if VM configuration file exists.
5176 # We need that when migration VMs to other nodes (files already moved)
5177 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5179 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5181 $force = 1 if !defined($force) && !$shutdown;
5184 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5185 kill 15, $pid if $pid;
5186 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5187 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5191 PVE
::QemuConfig-
>lock_config($vmid, sub {
5193 my $pid = check_running
($vmid, $nocheck);
5198 $conf = PVE
::QemuConfig-
>load_config($vmid);
5199 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5200 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5201 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5202 $timeout = $opts->{down
} if $opts->{down
};
5206 $timeout = 60 if !defined($timeout);
5210 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5211 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5213 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5216 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5223 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5228 if ($count >= $timeout) {
5230 warn "VM still running - terminating now with SIGTERM\n";
5233 die "VM quit/powerdown failed - got timeout\n";
5236 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5241 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5244 die "VM quit/powerdown failed\n";
5252 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5257 if ($count >= $timeout) {
5258 warn "VM still running - terminating now with SIGKILL\n";
5263 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5268 my ($vmid, $skiplock) = @_;
5270 PVE
::QemuConfig-
>lock_config($vmid, sub {
5272 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5274 PVE
::QemuConfig-
>check_lock($conf)
5275 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5277 vm_mon_cmd
($vmid, "stop");
5282 my ($vmid, $skiplock, $nocheck) = @_;
5284 PVE
::QemuConfig-
>lock_config($vmid, sub {
5286 my $res = vm_mon_cmd
($vmid, 'query-status');
5287 my $resume_cmd = 'cont';
5289 if ($res->{status
} && $res->{status
} eq 'suspended') {
5290 $resume_cmd = 'system_wakeup';
5295 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5297 PVE
::QemuConfig-
>check_lock($conf)
5298 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5300 vm_mon_cmd
($vmid, $resume_cmd);
5303 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5309 my ($vmid, $skiplock, $key) = @_;
5311 PVE
::QemuConfig-
>lock_config($vmid, sub {
5313 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5315 # there is no qmp command, so we use the human monitor command
5316 vm_human_monitor_command
($vmid, "sendkey $key");
5321 my ($storecfg, $vmid, $skiplock) = @_;
5323 PVE
::QemuConfig-
>lock_config($vmid, sub {
5325 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5327 if (!check_running
($vmid)) {
5328 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5330 die "VM $vmid is running - destroy failed\n";
5338 my ($filename, $buf) = @_;
5340 my $fh = IO
::File-
>new($filename, "w");
5341 return undef if !$fh;
5343 my $res = print $fh $buf;
5350 sub pci_device_info
{
5355 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5356 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5358 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5359 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5361 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5362 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5364 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5365 return undef if !defined($product) || $product !~ s/^0x//;
5370 product
=> $product,
5376 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5385 my $name = $dev->{name
};
5387 my $fn = "$pcisysfs/devices/$name/reset";
5389 return file_write
($fn, "1");
5392 sub pci_dev_bind_to_vfio
{
5395 my $name = $dev->{name
};
5397 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5399 if (!-d
$vfio_basedir) {
5400 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5402 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5404 my $testdir = "$vfio_basedir/$name";
5405 return 1 if -d
$testdir;
5407 my $data = "$dev->{vendor} $dev->{product}";
5408 return undef if !file_write
("$vfio_basedir/new_id", $data);
5410 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5411 if (!file_write
($fn, $name)) {
5412 return undef if -f
$fn;
5415 $fn = "$vfio_basedir/bind";
5416 if (! -d
$testdir) {
5417 return undef if !file_write
($fn, $name);
5423 sub pci_dev_group_bind_to_vfio
{
5426 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5428 if (!-d
$vfio_basedir) {
5429 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5431 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5433 # get IOMMU group devices
5434 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5435 my @devs = grep /^0000:/, readdir($D);
5438 foreach my $pciid (@devs) {
5439 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5441 # pci bridges, switches or root ports are not supported
5442 # they have a pci_bus subdirectory so skip them
5443 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5445 my $info = pci_device_info
($1);
5446 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5452 # vzdump restore implementaion
5454 sub tar_archive_read_firstfile
{
5455 my $archive = shift;
5457 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5459 # try to detect archive type first
5460 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5461 die "unable to open file '$archive'\n";
5462 my $firstfile = <$fh>;
5466 die "ERROR: archive contaions no data\n" if !$firstfile;
5472 sub tar_restore_cleanup
{
5473 my ($storecfg, $statfile) = @_;
5475 print STDERR
"starting cleanup\n";
5477 if (my $fd = IO
::File-
>new($statfile, "r")) {
5478 while (defined(my $line = <$fd>)) {
5479 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5482 if ($volid =~ m
|^/|) {
5483 unlink $volid || die 'unlink failed\n';
5485 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5487 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5489 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5491 print STDERR
"unable to parse line in statfile - $line";
5498 sub restore_archive
{
5499 my ($archive, $vmid, $user, $opts) = @_;
5501 my $format = $opts->{format
};
5504 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5505 $format = 'tar' if !$format;
5507 } elsif ($archive =~ m/\.tar$/) {
5508 $format = 'tar' if !$format;
5509 } elsif ($archive =~ m/.tar.lzo$/) {
5510 $format = 'tar' if !$format;
5512 } elsif ($archive =~ m/\.vma$/) {
5513 $format = 'vma' if !$format;
5514 } elsif ($archive =~ m/\.vma\.gz$/) {
5515 $format = 'vma' if !$format;
5517 } elsif ($archive =~ m/\.vma\.lzo$/) {
5518 $format = 'vma' if !$format;
5521 $format = 'vma' if !$format; # default
5524 # try to detect archive format
5525 if ($format eq 'tar') {
5526 return restore_tar_archive
($archive, $vmid, $user, $opts);
5528 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5532 sub restore_update_config_line
{
5533 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5535 return if $line =~ m/^\#qmdump\#/;
5536 return if $line =~ m/^\#vzdump\#/;
5537 return if $line =~ m/^lock:/;
5538 return if $line =~ m/^unused\d+:/;
5539 return if $line =~ m/^parent:/;
5540 return if $line =~ m/^template:/; # restored VM is never a template
5542 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5543 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5544 # try to convert old 1.X settings
5545 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5546 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5547 my ($model, $macaddr) = split(/\=/, $devconfig);
5548 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5551 bridge
=> "vmbr$ind",
5552 macaddr
=> $macaddr,
5554 my $netstr = print_net
($net);
5556 print $outfd "net$cookie->{netcount}: $netstr\n";
5557 $cookie->{netcount
}++;
5559 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5560 my ($id, $netstr) = ($1, $2);
5561 my $net = parse_net
($netstr);
5562 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5563 $netstr = print_net
($net);
5564 print $outfd "$id: $netstr\n";
5565 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5568 my $di = parse_drive
($virtdev, $value);
5569 if (defined($di->{backup
}) && !$di->{backup
}) {
5570 print $outfd "#$line";
5571 } elsif ($map->{$virtdev}) {
5572 delete $di->{format
}; # format can change on restore
5573 $di->{file
} = $map->{$virtdev};
5574 $value = print_drive
($vmid, $di);
5575 print $outfd "$virtdev: $value\n";
5579 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5581 if ($vmgenid ne '0') {
5582 # always generate a new vmgenid if there was a valid one setup
5583 $vmgenid = generate_uuid
();
5585 print $outfd "vmgenid: $vmgenid\n";
5586 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5587 my ($uuid, $uuid_str);
5588 UUID
::generate
($uuid);
5589 UUID
::unparse
($uuid, $uuid_str);
5590 my $smbios1 = parse_smbios1
($2);
5591 $smbios1->{uuid
} = $uuid_str;
5592 print $outfd $1.print_smbios1
($smbios1)."\n";
5599 my ($cfg, $vmid) = @_;
5601 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5603 my $volid_hash = {};
5604 foreach my $storeid (keys %$info) {
5605 foreach my $item (@{$info->{$storeid}}) {
5606 next if !($item->{volid
} && $item->{size
});
5607 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5608 $volid_hash->{$item->{volid
}} = $item;
5615 sub is_volume_in_use
{
5616 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5618 my $path = PVE
::Storage
::path
($storecfg, $volid);
5620 my $scan_config = sub {
5621 my ($cref, $snapname) = @_;
5623 foreach my $key (keys %$cref) {
5624 my $value = $cref->{$key};
5625 if (is_valid_drivename
($key)) {
5626 next if $skip_drive && $key eq $skip_drive;
5627 my $drive = parse_drive
($key, $value);
5628 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5629 return 1 if $volid eq $drive->{file
};
5630 if ($drive->{file
} =~ m!^/!) {
5631 return 1 if $drive->{file
} eq $path;
5633 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5635 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5637 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5645 return 1 if &$scan_config($conf);
5649 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5650 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5656 sub update_disksize
{
5657 my ($vmid, $conf, $volid_hash) = @_;
5660 my $prefix = "VM $vmid:";
5662 # used and unused disks
5663 my $referenced = {};
5665 # Note: it is allowed to define multiple storages with same path (alias), so
5666 # we need to check both 'volid' and real 'path' (two different volid can point
5667 # to the same path).
5669 my $referencedpath = {};
5672 foreach my $opt (keys %$conf) {
5673 if (is_valid_drivename
($opt)) {
5674 my $drive = parse_drive
($opt, $conf->{$opt});
5675 my $volid = $drive->{file
};
5678 $referenced->{$volid} = 1;
5679 if ($volid_hash->{$volid} &&
5680 (my $path = $volid_hash->{$volid}->{path
})) {
5681 $referencedpath->{$path} = 1;
5684 next if drive_is_cdrom
($drive);
5685 next if !$volid_hash->{$volid};
5687 $drive->{size
} = $volid_hash->{$volid}->{size
};
5688 my $new = print_drive
($vmid, $drive);
5689 if ($new ne $conf->{$opt}) {
5691 $conf->{$opt} = $new;
5692 print "$prefix update disk '$opt' information.\n";
5697 # remove 'unusedX' entry if volume is used
5698 foreach my $opt (keys %$conf) {
5699 next if $opt !~ m/^unused\d+$/;
5700 my $volid = $conf->{$opt};
5701 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5702 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5703 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5705 delete $conf->{$opt};
5708 $referenced->{$volid} = 1;
5709 $referencedpath->{$path} = 1 if $path;
5712 foreach my $volid (sort keys %$volid_hash) {
5713 next if $volid =~ m/vm-$vmid-state-/;
5714 next if $referenced->{$volid};
5715 my $path = $volid_hash->{$volid}->{path
};
5716 next if !$path; # just to be sure
5717 next if $referencedpath->{$path};
5719 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5720 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5721 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5728 my ($vmid, $nolock, $dryrun) = @_;
5730 my $cfg = PVE
::Storage
::config
();
5732 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5733 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5734 foreach my $stor (keys %{$cfg->{ids
}}) {
5735 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5738 print "rescan volumes...\n";
5739 my $volid_hash = scan_volids
($cfg, $vmid);
5741 my $updatefn = sub {
5744 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5746 PVE
::QemuConfig-
>check_lock($conf);
5749 foreach my $volid (keys %$volid_hash) {
5750 my $info = $volid_hash->{$volid};
5751 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5754 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5756 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5759 if (defined($vmid)) {
5763 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5766 my $vmlist = config_list
();
5767 foreach my $vmid (keys %$vmlist) {
5771 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5777 sub restore_vma_archive
{
5778 my ($archive, $vmid, $user, $opts, $comp) = @_;
5780 my $readfrom = $archive;
5782 my $cfg = PVE
::Storage
::config
();
5784 my $bwlimit = $opts->{bwlimit
};
5786 my $dbg_cmdstring = '';
5787 my $add_pipe = sub {
5789 push @$commands, $cmd;
5790 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5791 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5796 if ($archive eq '-') {
5799 # If we use a backup from a PVE defined storage we also consider that
5800 # storage's rate limit:
5801 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5802 if (defined($volid)) {
5803 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5804 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5806 print STDERR
"applying read rate limit: $readlimit\n";
5807 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5808 $add_pipe->($cstream);
5815 if ($comp eq 'gzip') {
5816 $cmd = ['zcat', $readfrom];
5817 } elsif ($comp eq 'lzop') {
5818 $cmd = ['lzop', '-d', '-c', $readfrom];
5820 die "unknown compression method '$comp'\n";
5825 my $tmpdir = "/var/tmp/vzdumptmp$$";
5828 # disable interrupts (always do cleanups)
5832 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5834 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5835 POSIX
::mkfifo
($mapfifo, 0600);
5838 my $openfifo = sub {
5839 open($fifofh, '>', $mapfifo) || die $!;
5842 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5849 my $rpcenv = PVE
::RPCEnvironment
::get
();
5851 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5852 my $tmpfn = "$conffile.$$.tmp";
5854 # Note: $oldconf is undef if VM does not exists
5855 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5856 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5860 my $print_devmap = sub {
5861 my $virtdev_hash = {};
5863 my $cfgfn = "$tmpdir/qemu-server.conf";
5865 # we can read the config - that is already extracted
5866 my $fh = IO
::File-
>new($cfgfn, "r") ||
5867 "unable to read qemu-server.conf - $!\n";
5869 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5871 my $pve_firewall_dir = '/etc/pve/firewall';
5872 mkdir $pve_firewall_dir; # make sure the dir exists
5873 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5876 while (defined(my $line = <$fh>)) {
5877 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5878 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5879 die "archive does not contain data for drive '$virtdev'\n"
5880 if !$devinfo->{$devname};
5881 if (defined($opts->{storage
})) {
5882 $storeid = $opts->{storage
} || 'local';
5883 } elsif (!$storeid) {
5886 $format = 'raw' if !$format;
5887 $devinfo->{$devname}->{devname
} = $devname;
5888 $devinfo->{$devname}->{virtdev
} = $virtdev;
5889 $devinfo->{$devname}->{format
} = $format;
5890 $devinfo->{$devname}->{storeid
} = $storeid;
5892 # check permission on storage
5893 my $pool = $opts->{pool
}; # todo: do we need that?
5894 if ($user ne 'root@pam') {
5895 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5898 $storage_limits{$storeid} = $bwlimit;
5900 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5904 foreach my $key (keys %storage_limits) {
5905 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
5907 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
5908 $storage_limits{$key} = $limit * 1024;
5911 foreach my $devname (keys %$devinfo) {
5912 die "found no device mapping information for device '$devname'\n"
5913 if !$devinfo->{$devname}->{virtdev
};
5916 # create empty/temp config
5918 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5919 foreach_drive
($oldconf, sub {
5920 my ($ds, $drive) = @_;
5922 return if drive_is_cdrom
($drive);
5924 my $volid = $drive->{file
};
5926 return if !$volid || $volid =~ m
|^/|;
5928 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5929 return if !$path || !$owner || ($owner != $vmid);
5931 # Note: only delete disk we want to restore
5932 # other volumes will become unused
5933 if ($virtdev_hash->{$ds}) {
5934 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5941 # delete vmstate files
5942 # since after the restore we have no snapshots anymore
5943 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5944 my $snap = $oldconf->{snapshots
}->{$snapname};
5945 if ($snap->{vmstate
}) {
5946 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5955 foreach my $virtdev (sort keys %$virtdev_hash) {
5956 my $d = $virtdev_hash->{$virtdev};
5957 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5958 my $storeid = $d->{storeid
};
5959 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
5962 if (my $limit = $storage_limits{$storeid}) {
5963 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
5966 # test if requested format is supported
5967 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
5968 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5969 $d->{format
} = $defFormat if !$supported;
5971 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
5972 $d->{format
}, undef, $alloc_size);
5973 print STDERR
"new volume ID is '$volid'\n";
5974 $d->{volid
} = $volid;
5975 my $path = PVE
::Storage
::path
($cfg, $volid);
5977 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5979 my $write_zeros = 1;
5980 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5984 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5986 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5987 $map->{$virtdev} = $volid;
5990 $fh->seek(0, 0) || die "seek failed - $!\n";
5992 my $outfd = new IO
::File
($tmpfn, "w") ||
5993 die "unable to write config for VM $vmid\n";
5995 my $cookie = { netcount
=> 0 };
5996 while (defined(my $line = <$fh>)) {
5997 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6010 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6011 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6013 $oldtimeout = alarm($timeout);
6020 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6021 my ($dev_id, $size, $devname) = ($1, $2, $3);
6022 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6023 } elsif ($line =~ m/^CTIME: /) {
6024 # we correctly received the vma config, so we can disable
6025 # the timeout now for disk allocation (set to 10 minutes, so
6026 # that we always timeout if something goes wrong)
6029 print $fifofh "done\n";
6030 my $tmp = $oldtimeout || 0;
6031 $oldtimeout = undef;
6037 print "restore vma archive: $dbg_cmdstring\n";
6038 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6042 alarm($oldtimeout) if $oldtimeout;
6045 foreach my $devname (keys %$devinfo) {
6046 my $volid = $devinfo->{$devname}->{volid
};
6047 push @$vollist, $volid if $volid;
6050 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6058 foreach my $devname (keys %$devinfo) {
6059 my $volid = $devinfo->{$devname}->{volid
};
6062 if ($volid =~ m
|^/|) {
6063 unlink $volid || die 'unlink failed\n';
6065 PVE
::Storage
::vdisk_free
($cfg, $volid);
6067 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6069 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6076 rename($tmpfn, $conffile) ||
6077 die "unable to commit configuration file '$conffile'\n";
6079 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6081 eval { rescan
($vmid, 1); };
6085 sub restore_tar_archive
{
6086 my ($archive, $vmid, $user, $opts) = @_;
6088 if ($archive ne '-') {
6089 my $firstfile = tar_archive_read_firstfile
($archive);
6090 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6091 if $firstfile ne 'qemu-server.conf';
6094 my $storecfg = PVE
::Storage
::config
();
6096 # destroy existing data - keep empty config
6097 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6098 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6100 my $tocmd = "/usr/lib/qemu-server/qmextract";
6102 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6103 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6104 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6105 $tocmd .= ' --info' if $opts->{info
};
6107 # tar option "xf" does not autodetect compression when read from STDIN,
6108 # so we pipe to zcat
6109 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6110 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6112 my $tmpdir = "/var/tmp/vzdumptmp$$";
6115 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6116 local $ENV{VZDUMP_VMID
} = $vmid;
6117 local $ENV{VZDUMP_USER
} = $user;
6119 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6120 my $tmpfn = "$conffile.$$.tmp";
6122 # disable interrupts (always do cleanups)
6126 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6134 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6136 if ($archive eq '-') {
6137 print "extracting archive from STDIN\n";
6138 run_command
($cmd, input
=> "<&STDIN");
6140 print "extracting archive '$archive'\n";
6144 return if $opts->{info
};
6148 my $statfile = "$tmpdir/qmrestore.stat";
6149 if (my $fd = IO
::File-
>new($statfile, "r")) {
6150 while (defined (my $line = <$fd>)) {
6151 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6152 $map->{$1} = $2 if $1;
6154 print STDERR
"unable to parse line in statfile - $line\n";
6160 my $confsrc = "$tmpdir/qemu-server.conf";
6162 my $srcfd = new IO
::File
($confsrc, "r") ||
6163 die "unable to open file '$confsrc'\n";
6165 my $outfd = new IO
::File
($tmpfn, "w") ||
6166 die "unable to write config for VM $vmid\n";
6168 my $cookie = { netcount
=> 0 };
6169 while (defined (my $line = <$srcfd>)) {
6170 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6182 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6189 rename $tmpfn, $conffile ||
6190 die "unable to commit configuration file '$conffile'\n";
6192 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6194 eval { rescan
($vmid, 1); };
6198 sub foreach_storage_used_by_vm
{
6199 my ($conf, $func) = @_;
6203 foreach_drive
($conf, sub {
6204 my ($ds, $drive) = @_;
6205 return if drive_is_cdrom
($drive);
6207 my $volid = $drive->{file
};
6209 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6210 $sidhash->{$sid} = $sid if $sid;
6213 foreach my $sid (sort keys %$sidhash) {
6218 sub do_snapshots_with_qemu
{
6219 my ($storecfg, $volid) = @_;
6221 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6223 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6224 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6228 if ($volid =~ m/\.(qcow2|qed)$/){
6235 sub qga_check_running
{
6236 my ($vmid, $nowarn) = @_;
6238 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6240 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6246 sub template_create
{
6247 my ($vmid, $conf, $disk) = @_;
6249 my $storecfg = PVE
::Storage
::config
();
6251 foreach_drive
($conf, sub {
6252 my ($ds, $drive) = @_;
6254 return if drive_is_cdrom
($drive);
6255 return if $disk && $ds ne $disk;
6257 my $volid = $drive->{file
};
6258 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6260 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6261 $drive->{file
} = $voliddst;
6262 $conf->{$ds} = print_drive
($vmid, $drive);
6263 PVE
::QemuConfig-
>write_config($vmid, $conf);
6267 sub qemu_img_convert
{
6268 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6270 my $storecfg = PVE
::Storage
::config
();
6271 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6272 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6274 if ($src_storeid && $dst_storeid) {
6276 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6278 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6279 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6281 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6282 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6284 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6285 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6288 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6289 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6290 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6291 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6292 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6293 if ($is_zero_initialized) {
6294 push @$cmd, "zeroinit:$dst_path";
6296 push @$cmd, $dst_path;
6301 if($line =~ m/\((\S+)\/100\
%\)/){
6303 my $transferred = int($size * $percent / 100);
6304 my $remaining = $size - $transferred;
6306 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6311 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6313 die "copy failed: $err" if $err;
6317 sub qemu_img_format
{
6318 my ($scfg, $volname) = @_;
6320 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6327 sub qemu_drive_mirror
{
6328 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6330 $jobs = {} if !$jobs;
6334 $jobs->{"drive-$drive"} = {};
6336 if ($dst_volid =~ /^nbd:/) {
6337 $qemu_target = $dst_volid;
6340 my $storecfg = PVE
::Storage
::config
();
6341 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6343 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6345 $format = qemu_img_format
($dst_scfg, $dst_volname);
6347 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6349 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6352 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6353 $opts->{format
} = $format if $format;
6355 print "drive mirror is starting for drive-$drive\n";
6357 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6360 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6361 die "mirroring error: $err";
6364 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6367 sub qemu_drive_mirror_monitor
{
6368 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6371 my $err_complete = 0;
6374 die "storage migration timed out\n" if $err_complete > 300;
6376 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6378 my $running_mirror_jobs = {};
6379 foreach my $stat (@$stats) {
6380 next if $stat->{type
} ne 'mirror';
6381 $running_mirror_jobs->{$stat->{device
}} = $stat;
6384 my $readycounter = 0;
6386 foreach my $job (keys %$jobs) {
6388 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6389 print "$job : finished\n";
6390 delete $jobs->{$job};
6394 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6396 my $busy = $running_mirror_jobs->{$job}->{busy
};
6397 my $ready = $running_mirror_jobs->{$job}->{ready
};
6398 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6399 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6400 my $remaining = $total - $transferred;
6401 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6403 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6406 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6409 last if scalar(keys %$jobs) == 0;
6411 if ($readycounter == scalar(keys %$jobs)) {
6412 print "all mirroring jobs are ready \n";
6413 last if $skipcomplete; #do the complete later
6415 if ($vmiddst && $vmiddst != $vmid) {
6416 my $agent_running = $qga && qga_check_running
($vmid);
6417 if ($agent_running) {
6418 print "freeze filesystem\n";
6419 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6421 print "suspend vm\n";
6422 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6425 # if we clone a disk for a new target vm, we don't switch the disk
6426 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6428 if ($agent_running) {
6429 print "unfreeze filesystem\n";
6430 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6432 print "resume vm\n";
6433 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6439 foreach my $job (keys %$jobs) {
6440 # try to switch the disk if source and destination are on the same guest
6441 print "$job: Completing block job...\n";
6443 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6444 if ($@ =~ m/cannot be completed/) {
6445 print "$job: Block job cannot be completed, try again.\n";
6448 print "$job: Completed successfully.\n";
6449 $jobs->{$job}->{complete
} = 1;
6460 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6461 die "mirroring error: $err";
6466 sub qemu_blockjobs_cancel
{
6467 my ($vmid, $jobs) = @_;
6469 foreach my $job (keys %$jobs) {
6470 print "$job: Cancelling block job\n";
6471 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6472 $jobs->{$job}->{cancel
} = 1;
6476 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6478 my $running_jobs = {};
6479 foreach my $stat (@$stats) {
6480 $running_jobs->{$stat->{device
}} = $stat;
6483 foreach my $job (keys %$jobs) {
6485 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6486 print "$job: Done.\n";
6487 delete $jobs->{$job};
6491 last if scalar(keys %$jobs) == 0;
6498 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6499 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6504 print "create linked clone of drive $drivename ($drive->{file})\n";
6505 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6506 push @$newvollist, $newvolid;
6509 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6510 $storeid = $storage if $storage;
6512 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6513 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6515 print "create full clone of drive $drivename ($drive->{file})\n";
6517 if (drive_is_cloudinit
($drive)) {
6518 $name = "vm-$newvmid-cloudinit";
6519 # cloudinit only supports raw and qcow2 atm:
6520 if ($dst_format eq 'qcow2') {
6522 } elsif ($dst_format ne 'raw') {
6523 die "clone: unhandled format for cloudinit image\n";
6526 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6527 push @$newvollist, $newvolid;
6529 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6531 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6532 if (!$running || $snapname) {
6533 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6536 my $kvmver = get_running_qemu_version
($vmid);
6537 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6538 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6539 if $drive->{iothread
};
6542 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6546 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6549 $disk->{format
} = undef;
6550 $disk->{file
} = $newvolid;
6551 $disk->{size
} = $size;
6556 # this only works if VM is running
6557 sub get_current_qemu_machine
{
6560 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6561 my $res = vm_qmp_command
($vmid, $cmd);
6563 my ($current, $default);
6564 foreach my $e (@$res) {
6565 $default = $e->{name
} if $e->{'is-default'};
6566 $current = $e->{name
} if $e->{'is-current'};
6569 # fallback to the default machine if current is not supported by qemu
6570 return $current || $default || 'pc';
6573 sub get_running_qemu_version
{
6575 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6576 my $res = vm_qmp_command
($vmid, $cmd);
6577 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6580 sub qemu_machine_feature_enabled
{
6581 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6586 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6588 $current_major = $3;
6589 $current_minor = $4;
6591 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6593 $current_major = $1;
6594 $current_minor = $2;
6597 return 1 if $current_major > $version_major ||
6598 ($current_major == $version_major &&
6599 $current_minor >= $version_minor);
6602 sub qemu_machine_pxe
{
6603 my ($vmid, $conf, $machine) = @_;
6605 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6607 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6614 sub qemu_use_old_bios_files
{
6615 my ($machine_type) = @_;
6617 return if !$machine_type;
6619 my $use_old_bios_files = undef;
6621 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6623 $use_old_bios_files = 1;
6625 my $kvmver = kvm_user_version
();
6626 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6627 # load new efi bios files on migration. So this hack is required to allow
6628 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6629 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6630 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6633 return ($use_old_bios_files, $machine_type);
6636 sub create_efidisk
{
6637 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6639 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6641 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6642 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6643 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6645 my $path = PVE
::Storage
::path
($storecfg, $volid);
6647 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6649 die "Copying EFI vars image failed: $@" if $@;
6651 return ($volid, $vars_size);
6658 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6659 my (undef, $id, $function) = @_;
6660 my $res = { id
=> $id, function
=> $function};
6661 push @{$devices->{$id}}, $res;
6664 # Entries should be sorted by functions.
6665 foreach my $id (keys %$devices) {
6666 my $dev = $devices->{$id};
6667 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6673 sub vm_iothreads_list
{
6676 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6679 foreach my $iothread (@$res) {
6680 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6687 my ($conf, $drive) = @_;
6691 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6693 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6699 my $controller = int($drive->{index} / $maxdev);
6700 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6702 return ($maxdev, $controller, $controller_prefix);
6705 sub add_hyperv_enlightenments
{
6706 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6708 return if $winversion < 6;
6709 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6711 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6713 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6714 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6715 push @$cpuFlags , 'hv_vapic';
6716 push @$cpuFlags , 'hv_time';
6718 push @$cpuFlags , 'hv_spinlocks=0xffff';
6721 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6722 push @$cpuFlags , 'hv_reset';
6723 push @$cpuFlags , 'hv_vpindex';
6724 push @$cpuFlags , 'hv_runtime';
6727 if ($winversion >= 7) {
6728 push @$cpuFlags , 'hv_relaxed';
6730 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 3, 0)) {
6731 push @$cpuFlags , 'hv_synic';
6732 push @$cpuFlags , 'hv_stimer';
6737 sub windows_version
{
6740 return 0 if !$ostype;
6744 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6746 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6748 } elsif ($ostype =~ m/^win(\d+)$/) {
6755 sub resolve_dst_disk_format
{
6756 my ($storecfg, $storeid, $src_volname, $format) = @_;
6757 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6760 # if no target format is specified, use the source disk format as hint
6762 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6763 $format = qemu_img_format
($scfg, $src_volname);
6769 # test if requested format is supported - else use default
6770 my $supported = grep { $_ eq $format } @$validFormats;
6771 $format = $defFormat if !$supported;
6775 sub resolve_first_disk
{
6777 my @disks = PVE
::QemuServer
::valid_drive_names
();
6779 foreach my $ds (reverse @disks) {
6780 next if !$conf->{$ds};
6781 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6782 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6789 my ($uuid, $uuid_str);
6790 UUID
::generate
($uuid);
6791 UUID
::unparse
($uuid, $uuid_str);
6795 sub generate_smbios1_uuid
{
6796 return "uuid=".generate_uuid
();
6799 # bash completion helper
6801 sub complete_backup_archives
{
6802 my ($cmdname, $pname, $cvalue) = @_;
6804 my $cfg = PVE
::Storage
::config
();
6808 if ($cvalue =~ m/^([^:]+):/) {
6812 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6815 foreach my $id (keys %$data) {
6816 foreach my $item (@{$data->{$id}}) {
6817 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6818 push @$res, $item->{volid
} if defined($item->{volid
});
6825 my $complete_vmid_full = sub {
6828 my $idlist = vmstatus
();
6832 foreach my $id (keys %$idlist) {
6833 my $d = $idlist->{$id};
6834 if (defined($running)) {
6835 next if $d->{template
};
6836 next if $running && $d->{status
} ne 'running';
6837 next if !$running && $d->{status
} eq 'running';
6846 return &$complete_vmid_full();
6849 sub complete_vmid_stopped
{
6850 return &$complete_vmid_full(0);
6853 sub complete_vmid_running
{
6854 return &$complete_vmid_full(1);
6857 sub complete_storage
{
6859 my $cfg = PVE
::Storage
::config
();
6860 my $ids = $cfg->{ids
};
6863 foreach my $sid (keys %$ids) {
6864 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6865 next if !$ids->{$sid}->{content
}->{images
};
6875 vm_mon_cmd
($vmid, 'nbd-server-stop');