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";
3203 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3204 my $eventsocket = qmp_socket
($vmid, 0, 'event');
3205 push @$cmd, '-chardev', "socket,id=qmp-event,path=$eventsocket,server,nowait";
3206 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3209 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3211 push @$cmd, '-daemonize';
3213 if ($conf->{smbios1
}) {
3214 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3217 if ($conf->{vmgenid
}) {
3218 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3221 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3222 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3226 if (my $efidisk = $conf->{efidisk0
}) {
3227 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3228 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3229 $format = $d->{format
};
3231 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3232 if (!defined($format)) {
3233 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3234 $format = qemu_img_format
($scfg, $volname);
3238 die "efidisk format must be specified\n"
3239 if !defined($format);
3242 warn "no efidisk configured! Using temporary efivars disk.\n";
3243 $path = "/tmp/$vmid-ovmf.fd";
3244 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3248 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3249 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3253 # add usb controllers
3254 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3255 push @$devices, @usbcontrollers if @usbcontrollers;
3256 my $vga = $conf->{vga
};
3258 my $qxlnum = vga_conf_has_spice
($vga);
3259 $vga = 'qxl' if $qxlnum;
3262 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3263 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3265 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3269 # enable absolute mouse coordinates (needed by vnc)
3271 if (defined($conf->{tablet
})) {
3272 $tablet = $conf->{tablet
};
3274 $tablet = $defaults->{tablet
};
3275 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3276 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3279 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3282 my $gpu_passthrough;
3285 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3286 my $d = parse_hostpci
($conf->{"hostpci$i"});
3289 my $pcie = $d->{pcie
};
3291 die "q35 machine model is not enabled" if !$q35;
3292 $pciaddr = print_pcie_addr
("hostpci$i");
3294 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3297 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3298 my $romfile = $d->{romfile
};
3301 if ($d->{'x-vga'}) {
3302 $xvga = ',x-vga=on';
3305 $gpu_passthrough = 1;
3307 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3311 my $pcidevices = $d->{pciid
};
3312 my $multifunction = 1 if @$pcidevices > 1;
3315 foreach my $pcidevice (@$pcidevices) {
3317 my $id = "hostpci$i";
3318 $id .= ".$j" if $multifunction;
3319 my $addr = $pciaddr;
3320 $addr .= ".$j" if $multifunction;
3321 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3324 $devicestr .= "$rombar$xvga";
3325 $devicestr .= ",multifunction=on" if $multifunction;
3326 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3329 push @$devices, '-device', $devicestr;
3335 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3336 push @$devices, @usbdevices if @usbdevices;
3338 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3339 if (my $path = $conf->{"serial$i"}) {
3340 if ($path eq 'socket') {
3341 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3342 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3343 push @$devices, '-device', "isa-serial,chardev=serial$i";
3345 die "no such serial device\n" if ! -c
$path;
3346 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3347 push @$devices, '-device', "isa-serial,chardev=serial$i";
3353 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3354 if (my $path = $conf->{"parallel$i"}) {
3355 die "no such parallel device\n" if ! -c
$path;
3356 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3357 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3358 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3364 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3365 $sockets = $conf->{sockets
} if $conf->{sockets
};
3367 my $cores = $conf->{cores
} || 1;
3369 my $maxcpus = $sockets * $cores;
3371 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3373 my $allowed_vcpus = $cpuinfo->{cpus
};
3375 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3376 if ($allowed_vcpus < $maxcpus);
3378 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3380 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3381 for (my $i = 2; $i <= $vcpus; $i++) {
3382 my $cpustr = print_cpu_device
($conf,$i);
3383 push @$cmd, '-device', $cpustr;
3388 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3390 push @$cmd, '-nodefaults';
3392 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3394 my $bootindex_hash = {};
3396 foreach my $o (split(//, $bootorder)) {
3397 $bootindex_hash->{$o} = $i*100;
3401 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3403 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3405 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3407 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3409 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3410 my $socket = vnc_socket
($vmid);
3411 push @$cmd, '-vnc', "unix:$socket,x509,password";
3413 push @$cmd, '-nographic';
3417 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3419 my $useLocaltime = $conf->{localtime};
3421 if ($winversion >= 5) { # windows
3422 $useLocaltime = 1 if !defined($conf->{localtime});
3424 # use time drift fix when acpi is enabled
3425 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3426 $tdf = 1 if !defined($conf->{tdf
});
3430 if ($winversion >= 6) {
3431 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3432 push @$cmd, '-no-hpet';
3435 push @$rtcFlags, 'driftfix=slew' if $tdf;
3438 push @$machineFlags, 'accel=tcg';
3441 if ($machine_type) {
3442 push @$machineFlags, "type=${machine_type}";
3445 if ($conf->{startdate
}) {
3446 push @$rtcFlags, "base=$conf->{startdate}";
3447 } elsif ($useLocaltime) {
3448 push @$rtcFlags, 'base=localtime';
3451 my $cpu = $kvm ?
"kvm64" : "qemu64";
3452 if (my $cputype = $conf->{cpu
}) {
3453 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3454 or die "Cannot parse cpu description: $cputype\n";
3455 $cpu = $cpuconf->{cputype
};
3456 $kvm_off = 1 if $cpuconf->{hidden
};
3458 if (defined(my $flags = $cpuconf->{flags
})) {
3459 push @$cpuFlags, split(";", $flags);
3463 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3465 push @$cpuFlags , '-x2apic'
3466 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3468 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3470 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3472 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3474 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3475 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3478 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3480 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3482 push @$cpuFlags, 'kvm=off' if $kvm_off;
3484 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3485 die "internal error"; # should not happen
3487 push @$cpuFlags, "vendor=${cpu_vendor}"
3488 if $cpu_vendor ne 'default';
3490 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3492 push @$cmd, '-cpu', $cpu;
3494 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3496 push @$cmd, '-S' if $conf->{freeze
};
3498 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3501 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3502 #push @$cmd, '-soundhw', 'es1370';
3503 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3505 if (parse_guest_agent
($conf)->{enabled
}) {
3506 my $qgasocket = qmp_socket
($vmid, 1);
3507 my $pciaddr = print_pci_addr
("qga0", $bridges);
3508 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3509 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3510 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3518 for(my $i = 1; $i < $qxlnum; $i++){
3519 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3520 push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3523 # assume other OS works like Linux
3524 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3525 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3529 my $pciaddr = print_pci_addr
("spice", $bridges);
3531 my $nodename = PVE
::INotify
::nodename
();
3532 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3533 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3534 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3535 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3536 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3538 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3540 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3541 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3542 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3545 # enable balloon by default, unless explicitly disabled
3546 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3547 $pciaddr = print_pci_addr
("balloon0", $bridges);
3548 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3551 if ($conf->{watchdog
}) {
3552 my $wdopts = parse_watchdog
($conf->{watchdog
});
3553 $pciaddr = print_pci_addr
("watchdog", $bridges);
3554 my $watchdog = $wdopts->{model
} || 'i6300esb';
3555 push @$devices, '-device', "$watchdog$pciaddr";
3556 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3560 my $scsicontroller = {};
3561 my $ahcicontroller = {};
3562 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3564 # Add iscsi initiator name if available
3565 if (my $initiator = get_initiator_name
()) {
3566 push @$devices, '-iscsi', "initiator-name=$initiator";
3569 foreach_drive
($conf, sub {
3570 my ($ds, $drive) = @_;
3572 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3573 push @$vollist, $drive->{file
};
3576 # ignore efidisk here, already added in bios/fw handling code above
3577 return if $drive->{interface
} eq 'efidisk';
3579 $use_virtio = 1 if $ds =~ m/^virtio/;
3581 if (drive_is_cdrom
($drive)) {
3582 if ($bootindex_hash->{d
}) {
3583 $drive->{bootindex
} = $bootindex_hash->{d
};
3584 $bootindex_hash->{d
} += 1;
3587 if ($bootindex_hash->{c
}) {
3588 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3589 $bootindex_hash->{c
} += 1;
3593 if($drive->{interface
} eq 'virtio'){
3594 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3597 if ($drive->{interface
} eq 'scsi') {
3599 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3601 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3602 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3605 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3606 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3607 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3608 } elsif ($drive->{iothread
}) {
3609 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3613 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3614 $queues = ",num_queues=$drive->{queues}";
3617 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3618 $scsicontroller->{$controller}=1;
3621 if ($drive->{interface
} eq 'sata') {
3622 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3623 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3624 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3625 $ahcicontroller->{$controller}=1;
3628 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3629 push @$devices, '-drive',$drive_cmd;
3630 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3633 for (my $i = 0; $i < $MAX_NETS; $i++) {
3634 next if !$conf->{"net$i"};
3635 my $d = parse_net
($conf->{"net$i"});
3638 $use_virtio = 1 if $d->{model
} eq 'virtio';
3640 if ($bootindex_hash->{n
}) {
3641 $d->{bootindex
} = $bootindex_hash->{n
};
3642 $bootindex_hash->{n
} += 1;
3645 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3646 push @$devices, '-netdev', $netdevfull;
3648 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3649 push @$devices, '-device', $netdevicefull;
3654 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3659 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3661 while (my ($k, $v) = each %$bridges) {
3662 $pciaddr = print_pci_addr
("pci.$k");
3663 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3668 if ($conf->{args
}) {
3669 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3673 push @$cmd, @$devices;
3674 push @$cmd, '-rtc', join(',', @$rtcFlags)
3675 if scalar(@$rtcFlags);
3676 push @$cmd, '-machine', join(',', @$machineFlags)
3677 if scalar(@$machineFlags);
3678 push @$cmd, '-global', join(',', @$globalFlags)
3679 if scalar(@$globalFlags);
3681 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3686 return "${var_run_tmpdir}/$vmid.vnc";
3692 my $res = vm_mon_cmd
($vmid, 'query-spice');
3694 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3698 my ($vmid, $qga, $name) = @_;
3699 my $sockettype = $qga ?
'qga' : 'qmp';
3700 my $ext = $name ?
'-'.$name : '';
3701 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3706 return "${var_run_tmpdir}/$vmid.pid";
3709 sub vm_devices_list
{
3712 my $res = vm_mon_cmd
($vmid, 'query-pci');
3713 my $devices_to_check = [];
3715 foreach my $pcibus (@$res) {
3716 push @$devices_to_check, @{$pcibus->{devices
}},
3719 while (@$devices_to_check) {
3721 for my $d (@$devices_to_check) {
3722 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3723 next if !$d->{'pci_bridge'};
3725 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3726 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3728 $devices_to_check = $to_check;
3731 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3732 foreach my $block (@$resblock) {
3733 if($block->{device
} =~ m/^drive-(\S+)/){
3738 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3739 foreach my $mice (@$resmice) {
3740 if ($mice->{name
} eq 'QEMU HID Tablet') {
3741 $devices->{tablet
} = 1;
3746 # for usb devices there is no query-usb
3747 # but we can iterate over the entries in
3748 # qom-list path=/machine/peripheral
3749 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3750 foreach my $per (@$resperipheral) {
3751 if ($per->{name
} =~ m/^usb\d+$/) {
3752 $devices->{$per->{name
}} = 1;
3760 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3762 my $q35 = machine_type_is_q35
($conf);
3764 my $devices_list = vm_devices_list
($vmid);
3765 return 1 if defined($devices_list->{$deviceid});
3767 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3769 if ($deviceid eq 'tablet') {
3771 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3773 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3775 die "usb hotplug currently not reliable\n";
3776 # since we can't reliably hot unplug all added usb devices
3777 # and usb passthrough disables live migration
3778 # we disable usb hotplugging for now
3779 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3781 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3783 qemu_iothread_add
($vmid, $deviceid, $device);
3785 qemu_driveadd
($storecfg, $vmid, $device);
3786 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3788 qemu_deviceadd
($vmid, $devicefull);
3789 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3791 eval { qemu_drivedel
($vmid, $deviceid); };
3796 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3799 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3800 my $pciaddr = print_pci_addr
($deviceid);
3801 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3803 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3805 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3806 qemu_iothread_add
($vmid, $deviceid, $device);
3807 $devicefull .= ",iothread=iothread-$deviceid";
3810 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3811 $devicefull .= ",num_queues=$device->{queues}";
3814 qemu_deviceadd
($vmid, $devicefull);
3815 qemu_deviceaddverify
($vmid, $deviceid);
3817 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3819 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3820 qemu_driveadd
($storecfg, $vmid, $device);
3822 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3823 eval { qemu_deviceadd
($vmid, $devicefull); };
3825 eval { qemu_drivedel
($vmid, $deviceid); };
3830 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3832 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3834 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3835 my $use_old_bios_files = undef;
3836 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3838 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3839 qemu_deviceadd
($vmid, $netdevicefull);
3840 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3842 eval { qemu_netdevdel
($vmid, $deviceid); };
3847 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3850 my $pciaddr = print_pci_addr
($deviceid);
3851 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3853 qemu_deviceadd
($vmid, $devicefull);
3854 qemu_deviceaddverify
($vmid, $deviceid);
3857 die "can't hotplug device '$deviceid'\n";
3863 # fixme: this should raise exceptions on error!
3864 sub vm_deviceunplug
{
3865 my ($vmid, $conf, $deviceid) = @_;
3867 my $devices_list = vm_devices_list
($vmid);
3868 return 1 if !defined($devices_list->{$deviceid});
3870 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3872 if ($deviceid eq 'tablet') {
3874 qemu_devicedel
($vmid, $deviceid);
3876 } elsif ($deviceid =~ m/^usb\d+$/) {
3878 die "usb hotplug currently not reliable\n";
3879 # when unplugging usb devices this way,
3880 # there may be remaining usb controllers/hubs
3881 # so we disable it for now
3882 qemu_devicedel
($vmid, $deviceid);
3883 qemu_devicedelverify
($vmid, $deviceid);
3885 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3887 qemu_devicedel
($vmid, $deviceid);
3888 qemu_devicedelverify
($vmid, $deviceid);
3889 qemu_drivedel
($vmid, $deviceid);
3890 qemu_iothread_del
($conf, $vmid, $deviceid);
3892 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3894 qemu_devicedel
($vmid, $deviceid);
3895 qemu_devicedelverify
($vmid, $deviceid);
3896 qemu_iothread_del
($conf, $vmid, $deviceid);
3898 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3900 qemu_devicedel
($vmid, $deviceid);
3901 qemu_drivedel
($vmid, $deviceid);
3902 qemu_deletescsihw
($conf, $vmid, $deviceid);
3904 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3906 qemu_devicedel
($vmid, $deviceid);
3907 qemu_devicedelverify
($vmid, $deviceid);
3908 qemu_netdevdel
($vmid, $deviceid);
3911 die "can't unplug device '$deviceid'\n";
3917 sub qemu_deviceadd
{
3918 my ($vmid, $devicefull) = @_;
3920 $devicefull = "driver=".$devicefull;
3921 my %options = split(/[=,]/, $devicefull);
3923 vm_mon_cmd
($vmid, "device_add" , %options);
3926 sub qemu_devicedel
{
3927 my ($vmid, $deviceid) = @_;
3929 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3932 sub qemu_iothread_add
{
3933 my($vmid, $deviceid, $device) = @_;
3935 if ($device->{iothread
}) {
3936 my $iothreads = vm_iothreads_list
($vmid);
3937 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3941 sub qemu_iothread_del
{
3942 my($conf, $vmid, $deviceid) = @_;
3944 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3945 if ($device->{iothread
}) {
3946 my $iothreads = vm_iothreads_list
($vmid);
3947 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3951 sub qemu_objectadd
{
3952 my($vmid, $objectid, $qomtype) = @_;
3954 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3959 sub qemu_objectdel
{
3960 my($vmid, $objectid) = @_;
3962 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3968 my ($storecfg, $vmid, $device) = @_;
3970 my $drive = print_drive_full
($storecfg, $vmid, $device);
3971 $drive =~ s/\\/\\\\/g;
3972 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3974 # If the command succeeds qemu prints: "OK
"
3975 return 1 if $ret =~ m/OK/s;
3977 die "adding drive failed
: $ret\n";
3981 my($vmid, $deviceid) = @_;
3983 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3986 return 1 if $ret eq "";
3988 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3989 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3991 die "deleting drive
$deviceid failed
: $ret\n";
3994 sub qemu_deviceaddverify {
3995 my ($vmid, $deviceid) = @_;
3997 for (my $i = 0; $i <= 5; $i++) {
3998 my $devices_list = vm_devices_list($vmid);
3999 return 1 if defined($devices_list->{$deviceid});
4003 die "error on hotplug device
'$deviceid'\n";
4007 sub qemu_devicedelverify {
4008 my ($vmid, $deviceid) = @_;
4010 # need to verify that the device is correctly removed as device_del
4011 # is async and empty return is not reliable
4013 for (my $i = 0; $i <= 5; $i++) {
4014 my $devices_list = vm_devices_list($vmid);
4015 return 1 if !defined($devices_list->{$deviceid});
4019 die "error on hot-unplugging device
'$deviceid'\n";
4022 sub qemu_findorcreatescsihw {
4023 my ($storecfg, $conf, $vmid, $device) = @_;
4025 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4027 my $scsihwid="$controller_prefix$controller";
4028 my $devices_list = vm_devices_list($vmid);
4030 if(!defined($devices_list->{$scsihwid})) {
4031 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
4037 sub qemu_deletescsihw {
4038 my ($conf, $vmid, $opt) = @_;
4040 my $device = parse_drive($opt, $conf->{$opt});
4042 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4043 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4047 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4049 my $devices_list = vm_devices_list($vmid);
4050 foreach my $opt (keys %{$devices_list}) {
4051 if (PVE::QemuServer::is_valid_drivename($opt)) {
4052 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4053 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4059 my $scsihwid="scsihw
$controller";
4061 vm_deviceunplug($vmid, $conf, $scsihwid);
4066 sub qemu_add_pci_bridge {
4067 my ($storecfg, $conf, $vmid, $device) = @_;
4073 print_pci_addr($device, $bridges);
4075 while (my ($k, $v) = each %$bridges) {
4078 return 1 if !defined($bridgeid) || $bridgeid < 1;
4080 my $bridge = "pci
.$bridgeid";
4081 my $devices_list = vm_devices_list($vmid);
4083 if (!defined($devices_list->{$bridge})) {
4084 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
4090 sub qemu_set_link_status {
4091 my ($vmid, $device, $up) = @_;
4093 vm_mon_cmd($vmid, "set_link
", name => $device,
4094 up => $up ? JSON::true : JSON::false);
4097 sub qemu_netdevadd {
4098 my ($vmid, $conf, $device, $deviceid) = @_;
4100 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
4101 my %options = split(/[=,]/, $netdev);
4103 vm_mon_cmd($vmid, "netdev_add
", %options);
4107 sub qemu_netdevdel {
4108 my ($vmid, $deviceid) = @_;
4110 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4113 sub qemu_usb_hotplug {
4114 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4118 # remove the old one first
4119 vm_deviceunplug($vmid, $conf, $deviceid);
4121 # check if xhci controller is necessary and available
4122 if ($device->{usb3}) {
4124 my $devicelist = vm_devices_list($vmid);
4126 if (!$devicelist->{xhci}) {
4127 my $pciaddr = print_pci_addr("xhci
");
4128 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4131 my $d = parse_usb_device($device->{host});
4132 $d->{usb3} = $device->{usb3};
4135 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4138 sub qemu_cpu_hotplug {
4139 my ($vmid, $conf, $vcpus) = @_;
4141 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4144 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4145 $sockets = $conf->{sockets} if $conf->{sockets};
4146 my $cores = $conf->{cores} || 1;
4147 my $maxcpus = $sockets * $cores;
4149 $vcpus = $maxcpus if !$vcpus;
4151 die "you can
't add more vcpus than maxcpus\n"
4152 if $vcpus > $maxcpus;
4154 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4156 if ($vcpus < $currentvcpus) {
4158 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4160 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4161 qemu_devicedel($vmid, "cpu$i");
4163 my $currentrunningvcpus = undef;
4165 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4166 last if scalar(@{$currentrunningvcpus}) == $i-1;
4167 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4171 #update conf after each succesfull cpu unplug
4172 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4173 PVE::QemuConfig->write_config($vmid, $conf);
4176 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4182 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4183 die "vcpus in running vm does not match its configuration\n"
4184 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4186 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4188 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4189 my $cpustr = print_cpu_device($conf, $i);
4190 qemu_deviceadd($vmid, $cpustr);
4193 my $currentrunningvcpus = undef;
4195 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4196 last if scalar(@{$currentrunningvcpus}) == $i;
4197 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4201 #update conf after each succesfull cpu hotplug
4202 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4203 PVE::QemuConfig->write_config($vmid, $conf);
4207 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4208 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4213 sub qemu_block_set_io_throttle {
4214 my ($vmid, $deviceid,
4215 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4216 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4217 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4218 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4220 return if !check_running($vmid) ;
4222 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4224 bps_rd => int($bps_rd),
4225 bps_wr => int($bps_wr),
4227 iops_rd => int($iops_rd),
4228 iops_wr => int($iops_wr),
4229 bps_max => int($bps_max),
4230 bps_rd_max => int($bps_rd_max),
4231 bps_wr_max => int($bps_wr_max),
4232 iops_max => int($iops_max),
4233 iops_rd_max => int($iops_rd_max),
4234 iops_wr_max => int($iops_wr_max),
4235 bps_max_length => int($bps_max_length),
4236 bps_rd_max_length => int($bps_rd_max_length),
4237 bps_wr_max_length => int($bps_wr_max_length),
4238 iops_max_length => int($iops_max_length),
4239 iops_rd_max_length => int($iops_rd_max_length),
4240 iops_wr_max_length => int($iops_wr_max_length),
4245 # old code, only used to shutdown old VM after update
4247 my ($fh, $timeout) = @_;
4249 my $sel = new IO::Select;
4256 while (scalar (@ready = $sel->can_read($timeout))) {
4258 if ($count = $fh->sysread($buf, 8192)) {
4259 if ($buf =~ /^(.*)\(qemu\) $/s) {
4266 if (!defined($count)) {
4273 die "monitor read timeout\n" if !scalar(@ready);
4278 sub qemu_block_resize {
4279 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4281 my $running = check_running($vmid);
4283 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4285 return if !$running;
4287 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4291 sub qemu_volume_snapshot {
4292 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4294 my $running = check_running($vmid);
4296 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4297 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4299 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4303 sub qemu_volume_snapshot_delete {
4304 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4306 my $running = check_running($vmid);
4311 my $conf = PVE::QemuConfig->load_config($vmid);
4312 foreach_drive($conf, sub {
4313 my ($ds, $drive) = @_;
4314 $running = 1 if $drive->{file} eq $volid;
4318 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4319 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4321 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4325 sub set_migration_caps {
4331 "auto-converge" => 1,
4333 "x-rdma-pin-all" => 0,
4338 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4340 for my $supported_capability (@$supported_capabilities) {
4342 capability => $supported_capability->{capability},
4343 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4347 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4350 my $fast_plug_option = {
4358 'vmstatestorage
' => 1,
4361 # hotplug changes in [PENDING]
4362 # $selection hash can be used to only apply specified options, for
4363 # example: { cores => 1 } (only apply changed 'cores
')
4364 # $errors ref is used to return error messages
4365 sub vmconfig_hotplug_pending {
4366 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4368 my $defaults = load_defaults();
4370 # commit values which do not have any impact on running VM first
4371 # Note: those option cannot raise errors, we we do not care about
4372 # $selection and always apply them.
4374 my $add_error = sub {
4375 my ($opt, $msg) = @_;
4376 $errors->{$opt} = "hotplug problem - $msg";
4380 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4381 if ($fast_plug_option->{$opt}) {
4382 $conf->{$opt} = $conf->{pending}->{$opt};
4383 delete $conf->{pending}->{$opt};
4389 PVE::QemuConfig->write_config($vmid, $conf);
4390 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4393 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4395 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4396 while (my ($opt, $force) = each %$pending_delete_hash) {
4397 next if $selection && !$selection->{$opt};
4399 if ($opt eq 'hotplug
') {
4400 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4401 } elsif ($opt eq 'tablet
') {
4402 die "skip\n" if !$hotplug_features->{usb};
4403 if ($defaults->{tablet}) {
4404 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4406 vm_deviceunplug($vmid, $conf, $opt);
4408 } elsif ($opt =~ m/^usb\d+/) {
4410 # since we cannot reliably hot unplug usb devices
4411 # we are disabling it
4412 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4413 vm_deviceunplug($vmid, $conf, $opt);
4414 } elsif ($opt eq 'vcpus
') {
4415 die "skip\n" if !$hotplug_features->{cpu};
4416 qemu_cpu_hotplug($vmid, $conf, undef);
4417 } elsif ($opt eq 'balloon
') {
4418 # enable balloon device is not hotpluggable
4419 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4420 # here we reset the ballooning value to memory
4421 my $balloon = $conf->{memory} || $defaults->{memory};
4422 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4423 } elsif ($fast_plug_option->{$opt}) {
4425 } elsif ($opt =~ m/^net(\d+)$/) {
4426 die "skip\n" if !$hotplug_features->{network};
4427 vm_deviceunplug($vmid, $conf, $opt);
4428 } elsif (is_valid_drivename($opt)) {
4429 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4430 vm_deviceunplug($vmid, $conf, $opt);
4431 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4432 } elsif ($opt =~ m/^memory$/) {
4433 die "skip\n" if !$hotplug_features->{memory};
4434 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4435 } elsif ($opt eq 'cpuunits
') {
4436 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4437 } elsif ($opt eq 'cpulimit
') {
4438 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4444 &$add_error($opt, $err) if $err ne "skip\n";
4446 # save new config if hotplug was successful
4447 delete $conf->{$opt};
4448 vmconfig_undelete_pending_option($conf, $opt);
4449 PVE::QemuConfig->write_config($vmid, $conf);
4450 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4454 my $apply_pending_cloudinit;
4455 $apply_pending_cloudinit = sub {
4456 my ($key, $value) = @_;
4457 $apply_pending_cloudinit = sub {}; # once is enough
4459 my @cloudinit_opts = keys %$confdesc_cloudinit;
4460 foreach my $opt (keys %{$conf->{pending}}) {
4461 next if !grep { $_ eq $opt } @cloudinit_opts;
4462 $conf->{$opt} = delete $conf->{pending}->{$opt};
4465 my $new_conf = { %$conf };
4466 $new_conf->{$key} = $value;
4467 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4470 foreach my $opt (keys %{$conf->{pending}}) {
4471 next if $selection && !$selection->{$opt};
4472 my $value = $conf->{pending}->{$opt};
4474 if ($opt eq 'hotplug
') {
4475 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4476 } elsif ($opt eq 'tablet
') {
4477 die "skip\n" if !$hotplug_features->{usb};
4479 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4480 } elsif ($value == 0) {
4481 vm_deviceunplug($vmid, $conf, $opt);
4483 } elsif ($opt =~ m/^usb\d+$/) {
4485 # since we cannot reliably hot unplug usb devices
4486 # we are disabling it
4487 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4488 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4489 die "skip\n" if !$d;
4490 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4491 } elsif ($opt eq 'vcpus
') {
4492 die "skip\n" if !$hotplug_features->{cpu};
4493 qemu_cpu_hotplug($vmid, $conf, $value);
4494 } elsif ($opt eq 'balloon
') {
4495 # enable/disable balloning device is not hotpluggable
4496 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4497 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4498 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4500 # allow manual ballooning if shares is set to zero
4501 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4502 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4503 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4505 } elsif ($opt =~ m/^net(\d+)$/) {
4506 # some changes can be done without hotplug
4507 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4508 $vmid, $opt, $value);
4509 } elsif (is_valid_drivename($opt)) {
4510 # some changes can be done without hotplug
4511 my $drive = parse_drive($opt, $value);
4512 if (drive_is_cloudinit($drive)) {
4513 &$apply_pending_cloudinit($opt, $value);
4515 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4516 $vmid, $opt, $value, 1);
4517 } elsif ($opt =~ m/^memory$/) { #dimms
4518 die "skip\n" if !$hotplug_features->{memory};
4519 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4520 } elsif ($opt eq 'cpuunits
') {
4521 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4522 } elsif ($opt eq 'cpulimit
') {
4523 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4524 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4526 die "skip\n"; # skip non-hot-pluggable options
4530 &$add_error($opt, $err) if $err ne "skip\n";
4532 # save new config if hotplug was successful
4533 $conf->{$opt} = $value;
4534 delete $conf->{pending}->{$opt};
4535 PVE::QemuConfig->write_config($vmid, $conf);
4536 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4541 sub try_deallocate_drive {
4542 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4544 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4545 my $volid = $drive->{file};
4546 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4547 my $sid = PVE::Storage::parse_volume_id($volid);
4548 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4550 # check if the disk is really unused
4551 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4552 if is_volume_in_use($storecfg, $conf, $key, $volid);
4553 PVE::Storage::vdisk_free($storecfg, $volid);
4556 # If vm is not owner of this disk remove from config
4564 sub vmconfig_delete_or_detach_drive {
4565 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4567 my $drive = parse_drive($opt, $conf->{$opt});
4569 my $rpcenv = PVE::RPCEnvironment::get();
4570 my $authuser = $rpcenv->get_user();
4573 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4574 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4576 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4580 sub vmconfig_apply_pending {
4581 my ($vmid, $conf, $storecfg) = @_;
4585 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4586 while (my ($opt, $force) = each %$pending_delete_hash) {
4587 die "internal error" if $opt =~ m/^unused/;
4588 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4589 if (!defined($conf->{$opt})) {
4590 vmconfig_undelete_pending_option($conf, $opt);
4591 PVE::QemuConfig->write_config($vmid, $conf);
4592 } elsif (is_valid_drivename($opt)) {
4593 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4594 vmconfig_undelete_pending_option($conf, $opt);
4595 delete $conf->{$opt};
4596 PVE::QemuConfig->write_config($vmid, $conf);
4598 vmconfig_undelete_pending_option($conf, $opt);
4599 delete $conf->{$opt};
4600 PVE::QemuConfig->write_config($vmid, $conf);
4604 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4606 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4607 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4609 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4610 # skip if nothing changed
4611 } elsif (is_valid_drivename($opt)) {
4612 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4613 if defined($conf->{$opt});
4614 $conf->{$opt} = $conf->{pending}->{$opt};
4616 $conf->{$opt} = $conf->{pending}->{$opt};
4619 delete $conf->{pending}->{$opt};
4620 PVE::QemuConfig->write_config($vmid, $conf);
4624 my $safe_num_ne = sub {
4627 return 0 if !defined($a) && !defined($b);
4628 return 1 if !defined($a);
4629 return 1 if !defined($b);
4634 my $safe_string_ne = sub {
4637 return 0 if !defined($a) && !defined($b);
4638 return 1 if !defined($a);
4639 return 1 if !defined($b);
4644 sub vmconfig_update_net {
4645 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4647 my $newnet = parse_net($value);
4649 if ($conf->{$opt}) {
4650 my $oldnet = parse_net($conf->{$opt});
4652 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4653 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4654 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4655 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4657 # for non online change, we try to hot-unplug
4658 die "skip\n" if !$hotplug;
4659 vm_deviceunplug($vmid, $conf, $opt);
4662 die "internal error" if $opt !~ m/net(\d+)/;
4663 my $iface = "tap${vmid}i$1";
4665 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4666 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4667 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4668 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4669 PVE::Network::tap_unplug($iface);
4670 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4671 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4672 # Rate can be applied on its own but any change above needs to
4673 # include the rate in tap_plug since OVS resets everything.
4674 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4677 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4678 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4686 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4692 sub vmconfig_update_disk {
4693 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4695 # fixme: do we need force?
4697 my $drive = parse_drive($opt, $value);
4699 if ($conf->{$opt}) {
4701 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4703 my $media = $drive->{media} || 'disk
';
4704 my $oldmedia = $old_drive->{media} || 'disk
';
4705 die "unable to change media type\n" if $media ne $oldmedia;
4707 if (!drive_is_cdrom($old_drive)) {
4709 if ($drive->{file} ne $old_drive->{file}) {
4711 die "skip\n" if !$hotplug;
4713 # unplug and register as unused
4714 vm_deviceunplug($vmid, $conf, $opt);
4715 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4718 # update existing disk
4720 # skip non hotpluggable value
4721 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4722 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4723 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4724 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4729 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4730 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4731 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4732 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4733 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4734 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4735 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4736 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4737 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4738 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4739 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4740 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4741 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4742 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4743 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4744 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4745 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4746 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4748 qemu_block_set_io_throttle($vmid,"drive-$opt",
4749 ($drive->{mbps} || 0)*1024*1024,
4750 ($drive->{mbps_rd} || 0)*1024*1024,
4751 ($drive->{mbps_wr} || 0)*1024*1024,
4752 $drive->{iops} || 0,
4753 $drive->{iops_rd} || 0,
4754 $drive->{iops_wr} || 0,
4755 ($drive->{mbps_max} || 0)*1024*1024,
4756 ($drive->{mbps_rd_max} || 0)*1024*1024,
4757 ($drive->{mbps_wr_max} || 0)*1024*1024,
4758 $drive->{iops_max} || 0,
4759 $drive->{iops_rd_max} || 0,
4760 $drive->{iops_wr_max} || 0,
4761 $drive->{bps_max_length} || 1,
4762 $drive->{bps_rd_max_length} || 1,
4763 $drive->{bps_wr_max_length} || 1,
4764 $drive->{iops_max_length} || 1,
4765 $drive->{iops_rd_max_length} || 1,
4766 $drive->{iops_wr_max_length} || 1);
4775 if ($drive->{file} eq 'none
') {
4776 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4777 if (drive_is_cloudinit($old_drive)) {
4778 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4781 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4782 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4783 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4791 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4793 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4794 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4798 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4799 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4801 PVE::QemuConfig->lock_config($vmid, sub {
4802 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4804 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4806 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4808 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4810 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4811 vmconfig_apply_pending($vmid, $conf, $storecfg);
4812 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4815 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4817 my $defaults = load_defaults();
4819 # set environment variable useful inside network script
4820 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4822 my $local_volumes = {};
4824 if ($targetstorage) {
4825 foreach_drive($conf, sub {
4826 my ($ds, $drive) = @_;
4828 return if drive_is_cdrom($drive);
4830 my $volid = $drive->{file};
4834 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4836 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4837 return if $scfg->{shared};
4838 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4843 foreach my $opt (sort keys %$local_volumes) {
4845 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4846 my $drive = parse_drive($opt, $conf->{$opt});
4848 #if remote storage is specified, use default format
4849 if ($targetstorage && $targetstorage ne "1") {
4850 $storeid = $targetstorage;
4851 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4852 $format = $defFormat;
4854 #else we use same format than original
4855 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4856 $format = qemu_img_format($scfg, $volid);
4859 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4860 my $newdrive = $drive;
4861 $newdrive->{format} = $format;
4862 $newdrive->{file} = $newvolid;
4863 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4864 $local_volumes->{$opt} = $drivestr;
4865 #pass drive to conf for command line
4866 $conf->{$opt} = $drivestr;
4870 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4872 my $migrate_port = 0;
4875 if ($statefile eq 'tcp
') {
4876 my $localip = "localhost";
4877 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4878 my $nodename = PVE::INotify::nodename();
4880 if (!defined($migration_type)) {
4881 if (defined($datacenterconf->{migration}->{type})) {
4882 $migration_type = $datacenterconf->{migration}->{type};
4884 $migration_type = 'secure
';
4888 if ($migration_type eq 'insecure
') {
4889 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4890 if ($migrate_network_addr) {
4891 $localip = $migrate_network_addr;
4893 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4896 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4899 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4900 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4901 $migrate_uri = "tcp:${localip}:${migrate_port}";
4902 push @$cmd, '-incoming
', $migrate_uri;
4905 } elsif ($statefile eq 'unix
') {
4906 # should be default for secure migrations as a ssh TCP forward
4907 # tunnel is not deterministic reliable ready and fails regurarly
4908 # to set up in time, so use UNIX socket forwards
4909 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4910 unlink $socket_addr;
4912 $migrate_uri = "unix:$socket_addr";
4914 push @$cmd, '-incoming
', $migrate_uri;
4918 push @$cmd, '-loadstate
', $statefile;
4925 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4926 my $d = parse_hostpci($conf->{"hostpci$i"});
4928 my $pcidevices = $d->{pciid};
4929 foreach my $pcidevice (@$pcidevices) {
4930 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4932 my $info = pci_device_info("0000:$pciid");
4933 die "IOMMU not present\n" if !check_iommu_support();
4934 die "no pci device info for device '$pciid'\n" if !$info;
4935 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4936 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4940 PVE::Storage::activate_volumes($storecfg, $vollist);
4942 if (!check_running($vmid, 1)) {
4944 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4945 outfunc => sub {}, errfunc => sub {});
4949 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4950 : $defaults->{cpuunits};
4952 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4953 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4956 Slice => 'qemu
.slice
',
4958 CPUShares => $cpuunits
4961 if (my $cpulimit = $conf->{cpulimit}) {
4962 $properties{CPUQuota} = int($cpulimit * 100);
4964 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4966 my $run_qemu = sub {
4967 PVE::Tools::run_fork sub {
4968 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4969 run_command($cmd, %run_params);
4973 if ($conf->{hugepages}) {
4976 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4977 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4979 PVE::QemuServer::Memory::hugepages_mount();
4980 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4982 eval { $run_qemu->() };
4984 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4988 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4990 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4993 eval { $run_qemu->() };
4997 # deactivate volumes if start fails
4998 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4999 die "start failed: $err";
5002 print "migration listens on $migrate_uri\n" if $migrate_uri;
5004 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5005 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5009 #start nbd server for storage migration
5010 if ($targetstorage) {
5011 my $nodename = PVE::INotify::nodename();
5012 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5013 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5014 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5015 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5017 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5019 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5021 foreach my $opt (sort keys %$local_volumes) {
5022 my $volid = $local_volumes->{$opt};
5023 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5024 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5025 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5029 if ($migratedfrom) {
5031 set_migration_caps($vmid);
5036 print "spice listens on port $spice_port\n";
5037 if ($spice_ticket) {
5038 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5039 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5044 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5045 if !$statefile && $conf->{balloon};
5047 foreach my $opt (keys %$conf) {
5048 next if $opt !~ m/^net\d+$/;
5049 my $nicconf = parse_net($conf->{$opt});
5050 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5054 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5055 path => "machine/peripheral/balloon0",
5056 property => "guest-stats-polling-interval",
5057 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5063 my ($vmid, $execute, %params) = @_;
5065 my $cmd = { execute => $execute, arguments => \%params };
5066 vm_qmp_command($vmid, $cmd);
5069 sub vm_mon_cmd_nocheck {
5070 my ($vmid, $execute, %params) = @_;
5072 my $cmd = { execute => $execute, arguments => \%params };
5073 vm_qmp_command($vmid, $cmd, 1);
5076 sub vm_qmp_command {
5077 my ($vmid, $cmd, $nocheck) = @_;
5082 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5083 $timeout = $cmd->{arguments}->{timeout};
5084 delete $cmd->{arguments}->{timeout};
5088 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5089 my $sname = qmp_socket($vmid);
5090 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5091 my $qmpclient = PVE::QMPClient->new();
5093 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5095 die "unable to open monitor socket\n";
5099 syslog("err", "VM $vmid qmp command failed - $err");
5106 sub vm_human_monitor_command {
5107 my ($vmid, $cmdline) = @_;
5112 execute => 'human-monitor-command
',
5113 arguments => { 'command-line
' => $cmdline},
5116 return vm_qmp_command($vmid, $cmd);
5119 sub vm_commandline {
5120 my ($storecfg, $vmid) = @_;
5122 my $conf = PVE::QemuConfig->load_config($vmid);
5124 my $defaults = load_defaults();
5126 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5128 return PVE::Tools::cmd2string($cmd);
5132 my ($vmid, $skiplock) = @_;
5134 PVE::QemuConfig->lock_config($vmid, sub {
5136 my $conf = PVE::QemuConfig->load_config($vmid);
5138 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5140 vm_mon_cmd($vmid, "system_reset");
5144 sub get_vm_volumes {
5148 foreach_volid($conf, sub {
5149 my ($volid, $attr) = @_;
5151 return if $volid =~ m|^/|;
5153 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5156 push @$vollist, $volid;
5162 sub vm_stop_cleanup {
5163 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5168 my $vollist = get_vm_volumes($conf);
5169 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5172 foreach my $ext (qw(mon qmp pid vnc qga)) {
5173 unlink "/var/run/qemu-server/${vmid}.$ext";
5176 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5178 warn $@ if $@; # avoid errors - just warn
5181 # Note: use $nockeck to skip tests if VM configuration file exists.
5182 # We need that when migration VMs to other nodes (files already moved)
5183 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5185 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5187 $force = 1 if !defined($force) && !$shutdown;
5190 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5191 kill 15, $pid if $pid;
5192 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5193 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5197 PVE
::QemuConfig-
>lock_config($vmid, sub {
5199 my $pid = check_running
($vmid, $nocheck);
5204 $conf = PVE
::QemuConfig-
>load_config($vmid);
5205 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5206 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5207 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5208 $timeout = $opts->{down
} if $opts->{down
};
5212 $timeout = 60 if !defined($timeout);
5216 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5217 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5219 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5222 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5229 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5234 if ($count >= $timeout) {
5236 warn "VM still running - terminating now with SIGTERM\n";
5239 die "VM quit/powerdown failed - got timeout\n";
5242 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5247 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5250 die "VM quit/powerdown failed\n";
5258 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5263 if ($count >= $timeout) {
5264 warn "VM still running - terminating now with SIGKILL\n";
5269 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5274 my ($vmid, $skiplock) = @_;
5276 PVE
::QemuConfig-
>lock_config($vmid, sub {
5278 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5280 PVE
::QemuConfig-
>check_lock($conf)
5281 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5283 vm_mon_cmd
($vmid, "stop");
5288 my ($vmid, $skiplock, $nocheck) = @_;
5290 PVE
::QemuConfig-
>lock_config($vmid, sub {
5292 my $res = vm_mon_cmd
($vmid, 'query-status');
5293 my $resume_cmd = 'cont';
5295 if ($res->{status
} && $res->{status
} eq 'suspended') {
5296 $resume_cmd = 'system_wakeup';
5301 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5303 PVE
::QemuConfig-
>check_lock($conf)
5304 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5306 vm_mon_cmd
($vmid, $resume_cmd);
5309 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5315 my ($vmid, $skiplock, $key) = @_;
5317 PVE
::QemuConfig-
>lock_config($vmid, sub {
5319 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5321 # there is no qmp command, so we use the human monitor command
5322 vm_human_monitor_command
($vmid, "sendkey $key");
5327 my ($storecfg, $vmid, $skiplock) = @_;
5329 PVE
::QemuConfig-
>lock_config($vmid, sub {
5331 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5333 if (!check_running
($vmid)) {
5334 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5336 die "VM $vmid is running - destroy failed\n";
5344 my ($filename, $buf) = @_;
5346 my $fh = IO
::File-
>new($filename, "w");
5347 return undef if !$fh;
5349 my $res = print $fh $buf;
5356 sub pci_device_info
{
5361 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5362 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5364 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5365 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5367 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5368 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5370 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5371 return undef if !defined($product) || $product !~ s/^0x//;
5376 product
=> $product,
5382 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5391 my $name = $dev->{name
};
5393 my $fn = "$pcisysfs/devices/$name/reset";
5395 return file_write
($fn, "1");
5398 sub pci_dev_bind_to_vfio
{
5401 my $name = $dev->{name
};
5403 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5405 if (!-d
$vfio_basedir) {
5406 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5408 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5410 my $testdir = "$vfio_basedir/$name";
5411 return 1 if -d
$testdir;
5413 my $data = "$dev->{vendor} $dev->{product}";
5414 return undef if !file_write
("$vfio_basedir/new_id", $data);
5416 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5417 if (!file_write
($fn, $name)) {
5418 return undef if -f
$fn;
5421 $fn = "$vfio_basedir/bind";
5422 if (! -d
$testdir) {
5423 return undef if !file_write
($fn, $name);
5429 sub pci_dev_group_bind_to_vfio
{
5432 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5434 if (!-d
$vfio_basedir) {
5435 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5437 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5439 # get IOMMU group devices
5440 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5441 my @devs = grep /^0000:/, readdir($D);
5444 foreach my $pciid (@devs) {
5445 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5447 # pci bridges, switches or root ports are not supported
5448 # they have a pci_bus subdirectory so skip them
5449 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5451 my $info = pci_device_info
($1);
5452 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5458 # vzdump restore implementaion
5460 sub tar_archive_read_firstfile
{
5461 my $archive = shift;
5463 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5465 # try to detect archive type first
5466 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5467 die "unable to open file '$archive'\n";
5468 my $firstfile = <$fh>;
5472 die "ERROR: archive contaions no data\n" if !$firstfile;
5478 sub tar_restore_cleanup
{
5479 my ($storecfg, $statfile) = @_;
5481 print STDERR
"starting cleanup\n";
5483 if (my $fd = IO
::File-
>new($statfile, "r")) {
5484 while (defined(my $line = <$fd>)) {
5485 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5488 if ($volid =~ m
|^/|) {
5489 unlink $volid || die 'unlink failed\n';
5491 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5493 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5495 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5497 print STDERR
"unable to parse line in statfile - $line";
5504 sub restore_archive
{
5505 my ($archive, $vmid, $user, $opts) = @_;
5507 my $format = $opts->{format
};
5510 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5511 $format = 'tar' if !$format;
5513 } elsif ($archive =~ m/\.tar$/) {
5514 $format = 'tar' if !$format;
5515 } elsif ($archive =~ m/.tar.lzo$/) {
5516 $format = 'tar' if !$format;
5518 } elsif ($archive =~ m/\.vma$/) {
5519 $format = 'vma' if !$format;
5520 } elsif ($archive =~ m/\.vma\.gz$/) {
5521 $format = 'vma' if !$format;
5523 } elsif ($archive =~ m/\.vma\.lzo$/) {
5524 $format = 'vma' if !$format;
5527 $format = 'vma' if !$format; # default
5530 # try to detect archive format
5531 if ($format eq 'tar') {
5532 return restore_tar_archive
($archive, $vmid, $user, $opts);
5534 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5538 sub restore_update_config_line
{
5539 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5541 return if $line =~ m/^\#qmdump\#/;
5542 return if $line =~ m/^\#vzdump\#/;
5543 return if $line =~ m/^lock:/;
5544 return if $line =~ m/^unused\d+:/;
5545 return if $line =~ m/^parent:/;
5546 return if $line =~ m/^template:/; # restored VM is never a template
5548 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5549 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5550 # try to convert old 1.X settings
5551 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5552 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5553 my ($model, $macaddr) = split(/\=/, $devconfig);
5554 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5557 bridge
=> "vmbr$ind",
5558 macaddr
=> $macaddr,
5560 my $netstr = print_net
($net);
5562 print $outfd "net$cookie->{netcount}: $netstr\n";
5563 $cookie->{netcount
}++;
5565 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5566 my ($id, $netstr) = ($1, $2);
5567 my $net = parse_net
($netstr);
5568 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5569 $netstr = print_net
($net);
5570 print $outfd "$id: $netstr\n";
5571 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5574 my $di = parse_drive
($virtdev, $value);
5575 if (defined($di->{backup
}) && !$di->{backup
}) {
5576 print $outfd "#$line";
5577 } elsif ($map->{$virtdev}) {
5578 delete $di->{format
}; # format can change on restore
5579 $di->{file
} = $map->{$virtdev};
5580 $value = print_drive
($vmid, $di);
5581 print $outfd "$virtdev: $value\n";
5585 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5587 if ($vmgenid ne '0') {
5588 # always generate a new vmgenid if there was a valid one setup
5589 $vmgenid = generate_uuid
();
5591 print $outfd "vmgenid: $vmgenid\n";
5592 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5593 my ($uuid, $uuid_str);
5594 UUID
::generate
($uuid);
5595 UUID
::unparse
($uuid, $uuid_str);
5596 my $smbios1 = parse_smbios1
($2);
5597 $smbios1->{uuid
} = $uuid_str;
5598 print $outfd $1.print_smbios1
($smbios1)."\n";
5605 my ($cfg, $vmid) = @_;
5607 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5609 my $volid_hash = {};
5610 foreach my $storeid (keys %$info) {
5611 foreach my $item (@{$info->{$storeid}}) {
5612 next if !($item->{volid
} && $item->{size
});
5613 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5614 $volid_hash->{$item->{volid
}} = $item;
5621 sub is_volume_in_use
{
5622 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5624 my $path = PVE
::Storage
::path
($storecfg, $volid);
5626 my $scan_config = sub {
5627 my ($cref, $snapname) = @_;
5629 foreach my $key (keys %$cref) {
5630 my $value = $cref->{$key};
5631 if (is_valid_drivename
($key)) {
5632 next if $skip_drive && $key eq $skip_drive;
5633 my $drive = parse_drive
($key, $value);
5634 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5635 return 1 if $volid eq $drive->{file
};
5636 if ($drive->{file
} =~ m!^/!) {
5637 return 1 if $drive->{file
} eq $path;
5639 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5641 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5643 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5651 return 1 if &$scan_config($conf);
5655 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5656 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5662 sub update_disksize
{
5663 my ($vmid, $conf, $volid_hash) = @_;
5666 my $prefix = "VM $vmid:";
5668 # used and unused disks
5669 my $referenced = {};
5671 # Note: it is allowed to define multiple storages with same path (alias), so
5672 # we need to check both 'volid' and real 'path' (two different volid can point
5673 # to the same path).
5675 my $referencedpath = {};
5678 foreach my $opt (keys %$conf) {
5679 if (is_valid_drivename
($opt)) {
5680 my $drive = parse_drive
($opt, $conf->{$opt});
5681 my $volid = $drive->{file
};
5684 $referenced->{$volid} = 1;
5685 if ($volid_hash->{$volid} &&
5686 (my $path = $volid_hash->{$volid}->{path
})) {
5687 $referencedpath->{$path} = 1;
5690 next if drive_is_cdrom
($drive);
5691 next if !$volid_hash->{$volid};
5693 $drive->{size
} = $volid_hash->{$volid}->{size
};
5694 my $new = print_drive
($vmid, $drive);
5695 if ($new ne $conf->{$opt}) {
5697 $conf->{$opt} = $new;
5698 print "$prefix update disk '$opt' information.\n";
5703 # remove 'unusedX' entry if volume is used
5704 foreach my $opt (keys %$conf) {
5705 next if $opt !~ m/^unused\d+$/;
5706 my $volid = $conf->{$opt};
5707 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5708 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5709 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5711 delete $conf->{$opt};
5714 $referenced->{$volid} = 1;
5715 $referencedpath->{$path} = 1 if $path;
5718 foreach my $volid (sort keys %$volid_hash) {
5719 next if $volid =~ m/vm-$vmid-state-/;
5720 next if $referenced->{$volid};
5721 my $path = $volid_hash->{$volid}->{path
};
5722 next if !$path; # just to be sure
5723 next if $referencedpath->{$path};
5725 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5726 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5727 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5734 my ($vmid, $nolock, $dryrun) = @_;
5736 my $cfg = PVE
::Storage
::config
();
5738 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5739 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5740 foreach my $stor (keys %{$cfg->{ids
}}) {
5741 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5744 print "rescan volumes...\n";
5745 my $volid_hash = scan_volids
($cfg, $vmid);
5747 my $updatefn = sub {
5750 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5752 PVE
::QemuConfig-
>check_lock($conf);
5755 foreach my $volid (keys %$volid_hash) {
5756 my $info = $volid_hash->{$volid};
5757 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5760 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5762 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5765 if (defined($vmid)) {
5769 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5772 my $vmlist = config_list
();
5773 foreach my $vmid (keys %$vmlist) {
5777 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5783 sub restore_vma_archive
{
5784 my ($archive, $vmid, $user, $opts, $comp) = @_;
5786 my $readfrom = $archive;
5788 my $cfg = PVE
::Storage
::config
();
5790 my $bwlimit = $opts->{bwlimit
};
5792 my $dbg_cmdstring = '';
5793 my $add_pipe = sub {
5795 push @$commands, $cmd;
5796 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5797 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5802 if ($archive eq '-') {
5805 # If we use a backup from a PVE defined storage we also consider that
5806 # storage's rate limit:
5807 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5808 if (defined($volid)) {
5809 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5810 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5812 print STDERR
"applying read rate limit: $readlimit\n";
5813 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5814 $add_pipe->($cstream);
5821 if ($comp eq 'gzip') {
5822 $cmd = ['zcat', $readfrom];
5823 } elsif ($comp eq 'lzop') {
5824 $cmd = ['lzop', '-d', '-c', $readfrom];
5826 die "unknown compression method '$comp'\n";
5831 my $tmpdir = "/var/tmp/vzdumptmp$$";
5834 # disable interrupts (always do cleanups)
5838 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5840 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5841 POSIX
::mkfifo
($mapfifo, 0600);
5844 my $openfifo = sub {
5845 open($fifofh, '>', $mapfifo) || die $!;
5848 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5855 my $rpcenv = PVE
::RPCEnvironment
::get
();
5857 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5858 my $tmpfn = "$conffile.$$.tmp";
5860 # Note: $oldconf is undef if VM does not exists
5861 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5862 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5866 my $print_devmap = sub {
5867 my $virtdev_hash = {};
5869 my $cfgfn = "$tmpdir/qemu-server.conf";
5871 # we can read the config - that is already extracted
5872 my $fh = IO
::File-
>new($cfgfn, "r") ||
5873 "unable to read qemu-server.conf - $!\n";
5875 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5877 my $pve_firewall_dir = '/etc/pve/firewall';
5878 mkdir $pve_firewall_dir; # make sure the dir exists
5879 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5882 while (defined(my $line = <$fh>)) {
5883 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5884 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5885 die "archive does not contain data for drive '$virtdev'\n"
5886 if !$devinfo->{$devname};
5887 if (defined($opts->{storage
})) {
5888 $storeid = $opts->{storage
} || 'local';
5889 } elsif (!$storeid) {
5892 $format = 'raw' if !$format;
5893 $devinfo->{$devname}->{devname
} = $devname;
5894 $devinfo->{$devname}->{virtdev
} = $virtdev;
5895 $devinfo->{$devname}->{format
} = $format;
5896 $devinfo->{$devname}->{storeid
} = $storeid;
5898 # check permission on storage
5899 my $pool = $opts->{pool
}; # todo: do we need that?
5900 if ($user ne 'root@pam') {
5901 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5904 $storage_limits{$storeid} = $bwlimit;
5906 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5910 foreach my $key (keys %storage_limits) {
5911 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
5913 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
5914 $storage_limits{$key} = $limit * 1024;
5917 foreach my $devname (keys %$devinfo) {
5918 die "found no device mapping information for device '$devname'\n"
5919 if !$devinfo->{$devname}->{virtdev
};
5922 # create empty/temp config
5924 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5925 foreach_drive
($oldconf, sub {
5926 my ($ds, $drive) = @_;
5928 return if drive_is_cdrom
($drive);
5930 my $volid = $drive->{file
};
5932 return if !$volid || $volid =~ m
|^/|;
5934 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5935 return if !$path || !$owner || ($owner != $vmid);
5937 # Note: only delete disk we want to restore
5938 # other volumes will become unused
5939 if ($virtdev_hash->{$ds}) {
5940 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5947 # delete vmstate files
5948 # since after the restore we have no snapshots anymore
5949 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5950 my $snap = $oldconf->{snapshots
}->{$snapname};
5951 if ($snap->{vmstate
}) {
5952 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5961 foreach my $virtdev (sort keys %$virtdev_hash) {
5962 my $d = $virtdev_hash->{$virtdev};
5963 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5964 my $storeid = $d->{storeid
};
5965 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
5968 if (my $limit = $storage_limits{$storeid}) {
5969 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
5972 # test if requested format is supported
5973 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
5974 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5975 $d->{format
} = $defFormat if !$supported;
5977 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
5978 $d->{format
}, undef, $alloc_size);
5979 print STDERR
"new volume ID is '$volid'\n";
5980 $d->{volid
} = $volid;
5981 my $path = PVE
::Storage
::path
($cfg, $volid);
5983 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5985 my $write_zeros = 1;
5986 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5990 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5992 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5993 $map->{$virtdev} = $volid;
5996 $fh->seek(0, 0) || die "seek failed - $!\n";
5998 my $outfd = new IO
::File
($tmpfn, "w") ||
5999 die "unable to write config for VM $vmid\n";
6001 my $cookie = { netcount
=> 0 };
6002 while (defined(my $line = <$fh>)) {
6003 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6016 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6017 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6019 $oldtimeout = alarm($timeout);
6026 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6027 my ($dev_id, $size, $devname) = ($1, $2, $3);
6028 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6029 } elsif ($line =~ m/^CTIME: /) {
6030 # we correctly received the vma config, so we can disable
6031 # the timeout now for disk allocation (set to 10 minutes, so
6032 # that we always timeout if something goes wrong)
6035 print $fifofh "done\n";
6036 my $tmp = $oldtimeout || 0;
6037 $oldtimeout = undef;
6043 print "restore vma archive: $dbg_cmdstring\n";
6044 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6048 alarm($oldtimeout) if $oldtimeout;
6051 foreach my $devname (keys %$devinfo) {
6052 my $volid = $devinfo->{$devname}->{volid
};
6053 push @$vollist, $volid if $volid;
6056 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6064 foreach my $devname (keys %$devinfo) {
6065 my $volid = $devinfo->{$devname}->{volid
};
6068 if ($volid =~ m
|^/|) {
6069 unlink $volid || die 'unlink failed\n';
6071 PVE
::Storage
::vdisk_free
($cfg, $volid);
6073 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6075 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6082 rename($tmpfn, $conffile) ||
6083 die "unable to commit configuration file '$conffile'\n";
6085 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6087 eval { rescan
($vmid, 1); };
6091 sub restore_tar_archive
{
6092 my ($archive, $vmid, $user, $opts) = @_;
6094 if ($archive ne '-') {
6095 my $firstfile = tar_archive_read_firstfile
($archive);
6096 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6097 if $firstfile ne 'qemu-server.conf';
6100 my $storecfg = PVE
::Storage
::config
();
6102 # destroy existing data - keep empty config
6103 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6104 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6106 my $tocmd = "/usr/lib/qemu-server/qmextract";
6108 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6109 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6110 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6111 $tocmd .= ' --info' if $opts->{info
};
6113 # tar option "xf" does not autodetect compression when read from STDIN,
6114 # so we pipe to zcat
6115 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6116 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6118 my $tmpdir = "/var/tmp/vzdumptmp$$";
6121 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6122 local $ENV{VZDUMP_VMID
} = $vmid;
6123 local $ENV{VZDUMP_USER
} = $user;
6125 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6126 my $tmpfn = "$conffile.$$.tmp";
6128 # disable interrupts (always do cleanups)
6132 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6140 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6142 if ($archive eq '-') {
6143 print "extracting archive from STDIN\n";
6144 run_command
($cmd, input
=> "<&STDIN");
6146 print "extracting archive '$archive'\n";
6150 return if $opts->{info
};
6154 my $statfile = "$tmpdir/qmrestore.stat";
6155 if (my $fd = IO
::File-
>new($statfile, "r")) {
6156 while (defined (my $line = <$fd>)) {
6157 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6158 $map->{$1} = $2 if $1;
6160 print STDERR
"unable to parse line in statfile - $line\n";
6166 my $confsrc = "$tmpdir/qemu-server.conf";
6168 my $srcfd = new IO
::File
($confsrc, "r") ||
6169 die "unable to open file '$confsrc'\n";
6171 my $outfd = new IO
::File
($tmpfn, "w") ||
6172 die "unable to write config for VM $vmid\n";
6174 my $cookie = { netcount
=> 0 };
6175 while (defined (my $line = <$srcfd>)) {
6176 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6188 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6195 rename $tmpfn, $conffile ||
6196 die "unable to commit configuration file '$conffile'\n";
6198 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6200 eval { rescan
($vmid, 1); };
6204 sub foreach_storage_used_by_vm
{
6205 my ($conf, $func) = @_;
6209 foreach_drive
($conf, sub {
6210 my ($ds, $drive) = @_;
6211 return if drive_is_cdrom
($drive);
6213 my $volid = $drive->{file
};
6215 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6216 $sidhash->{$sid} = $sid if $sid;
6219 foreach my $sid (sort keys %$sidhash) {
6224 sub do_snapshots_with_qemu
{
6225 my ($storecfg, $volid) = @_;
6227 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6229 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6230 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6234 if ($volid =~ m/\.(qcow2|qed)$/){
6241 sub qga_check_running
{
6242 my ($vmid, $nowarn) = @_;
6244 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6246 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6252 sub template_create
{
6253 my ($vmid, $conf, $disk) = @_;
6255 my $storecfg = PVE
::Storage
::config
();
6257 foreach_drive
($conf, sub {
6258 my ($ds, $drive) = @_;
6260 return if drive_is_cdrom
($drive);
6261 return if $disk && $ds ne $disk;
6263 my $volid = $drive->{file
};
6264 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6266 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6267 $drive->{file
} = $voliddst;
6268 $conf->{$ds} = print_drive
($vmid, $drive);
6269 PVE
::QemuConfig-
>write_config($vmid, $conf);
6273 sub qemu_img_convert
{
6274 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6276 my $storecfg = PVE
::Storage
::config
();
6277 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6278 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6280 if ($src_storeid && $dst_storeid) {
6282 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6284 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6285 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6287 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6288 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6290 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6291 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6294 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6295 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6296 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6297 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6298 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6299 if ($is_zero_initialized) {
6300 push @$cmd, "zeroinit:$dst_path";
6302 push @$cmd, $dst_path;
6307 if($line =~ m/\((\S+)\/100\
%\)/){
6309 my $transferred = int($size * $percent / 100);
6310 my $remaining = $size - $transferred;
6312 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6317 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6319 die "copy failed: $err" if $err;
6323 sub qemu_img_format
{
6324 my ($scfg, $volname) = @_;
6326 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6333 sub qemu_drive_mirror
{
6334 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6336 $jobs = {} if !$jobs;
6340 $jobs->{"drive-$drive"} = {};
6342 if ($dst_volid =~ /^nbd:/) {
6343 $qemu_target = $dst_volid;
6346 my $storecfg = PVE
::Storage
::config
();
6347 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6349 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6351 $format = qemu_img_format
($dst_scfg, $dst_volname);
6353 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6355 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6358 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6359 $opts->{format
} = $format if $format;
6361 print "drive mirror is starting for drive-$drive\n";
6363 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6366 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6367 die "mirroring error: $err";
6370 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6373 sub qemu_drive_mirror_monitor
{
6374 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6377 my $err_complete = 0;
6380 die "storage migration timed out\n" if $err_complete > 300;
6382 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6384 my $running_mirror_jobs = {};
6385 foreach my $stat (@$stats) {
6386 next if $stat->{type
} ne 'mirror';
6387 $running_mirror_jobs->{$stat->{device
}} = $stat;
6390 my $readycounter = 0;
6392 foreach my $job (keys %$jobs) {
6394 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6395 print "$job : finished\n";
6396 delete $jobs->{$job};
6400 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6402 my $busy = $running_mirror_jobs->{$job}->{busy
};
6403 my $ready = $running_mirror_jobs->{$job}->{ready
};
6404 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6405 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6406 my $remaining = $total - $transferred;
6407 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6409 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6412 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6415 last if scalar(keys %$jobs) == 0;
6417 if ($readycounter == scalar(keys %$jobs)) {
6418 print "all mirroring jobs are ready \n";
6419 last if $skipcomplete; #do the complete later
6421 if ($vmiddst && $vmiddst != $vmid) {
6422 my $agent_running = $qga && qga_check_running
($vmid);
6423 if ($agent_running) {
6424 print "freeze filesystem\n";
6425 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6427 print "suspend vm\n";
6428 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6431 # if we clone a disk for a new target vm, we don't switch the disk
6432 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6434 if ($agent_running) {
6435 print "unfreeze filesystem\n";
6436 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6438 print "resume vm\n";
6439 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6445 foreach my $job (keys %$jobs) {
6446 # try to switch the disk if source and destination are on the same guest
6447 print "$job: Completing block job...\n";
6449 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6450 if ($@ =~ m/cannot be completed/) {
6451 print "$job: Block job cannot be completed, try again.\n";
6454 print "$job: Completed successfully.\n";
6455 $jobs->{$job}->{complete
} = 1;
6466 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6467 die "mirroring error: $err";
6472 sub qemu_blockjobs_cancel
{
6473 my ($vmid, $jobs) = @_;
6475 foreach my $job (keys %$jobs) {
6476 print "$job: Cancelling block job\n";
6477 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6478 $jobs->{$job}->{cancel
} = 1;
6482 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6484 my $running_jobs = {};
6485 foreach my $stat (@$stats) {
6486 $running_jobs->{$stat->{device
}} = $stat;
6489 foreach my $job (keys %$jobs) {
6491 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6492 print "$job: Done.\n";
6493 delete $jobs->{$job};
6497 last if scalar(keys %$jobs) == 0;
6504 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6505 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6510 print "create linked clone of drive $drivename ($drive->{file})\n";
6511 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6512 push @$newvollist, $newvolid;
6515 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6516 $storeid = $storage if $storage;
6518 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6519 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6521 print "create full clone of drive $drivename ($drive->{file})\n";
6523 if (drive_is_cloudinit
($drive)) {
6524 $name = "vm-$newvmid-cloudinit";
6525 # cloudinit only supports raw and qcow2 atm:
6526 if ($dst_format eq 'qcow2') {
6528 } elsif ($dst_format ne 'raw') {
6529 die "clone: unhandled format for cloudinit image\n";
6532 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6533 push @$newvollist, $newvolid;
6535 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6537 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6538 if (!$running || $snapname) {
6539 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6542 my $kvmver = get_running_qemu_version
($vmid);
6543 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6544 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6545 if $drive->{iothread
};
6548 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6552 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6555 $disk->{format
} = undef;
6556 $disk->{file
} = $newvolid;
6557 $disk->{size
} = $size;
6562 # this only works if VM is running
6563 sub get_current_qemu_machine
{
6566 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6567 my $res = vm_qmp_command
($vmid, $cmd);
6569 my ($current, $default);
6570 foreach my $e (@$res) {
6571 $default = $e->{name
} if $e->{'is-default'};
6572 $current = $e->{name
} if $e->{'is-current'};
6575 # fallback to the default machine if current is not supported by qemu
6576 return $current || $default || 'pc';
6579 sub get_running_qemu_version
{
6581 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6582 my $res = vm_qmp_command
($vmid, $cmd);
6583 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6586 sub qemu_machine_feature_enabled
{
6587 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6592 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6594 $current_major = $3;
6595 $current_minor = $4;
6597 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6599 $current_major = $1;
6600 $current_minor = $2;
6603 return 1 if $current_major > $version_major ||
6604 ($current_major == $version_major &&
6605 $current_minor >= $version_minor);
6608 sub qemu_machine_pxe
{
6609 my ($vmid, $conf, $machine) = @_;
6611 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6613 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6620 sub qemu_use_old_bios_files
{
6621 my ($machine_type) = @_;
6623 return if !$machine_type;
6625 my $use_old_bios_files = undef;
6627 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6629 $use_old_bios_files = 1;
6631 my $kvmver = kvm_user_version
();
6632 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6633 # load new efi bios files on migration. So this hack is required to allow
6634 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6635 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6636 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6639 return ($use_old_bios_files, $machine_type);
6642 sub create_efidisk
{
6643 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6645 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6647 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6648 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6649 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6651 my $path = PVE
::Storage
::path
($storecfg, $volid);
6653 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6655 die "Copying EFI vars image failed: $@" if $@;
6657 return ($volid, $vars_size);
6664 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6665 my (undef, $id, $function) = @_;
6666 my $res = { id
=> $id, function
=> $function};
6667 push @{$devices->{$id}}, $res;
6670 # Entries should be sorted by functions.
6671 foreach my $id (keys %$devices) {
6672 my $dev = $devices->{$id};
6673 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6679 sub vm_iothreads_list
{
6682 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6685 foreach my $iothread (@$res) {
6686 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6693 my ($conf, $drive) = @_;
6697 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6699 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6705 my $controller = int($drive->{index} / $maxdev);
6706 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6708 return ($maxdev, $controller, $controller_prefix);
6711 sub add_hyperv_enlightenments
{
6712 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6714 return if $winversion < 6;
6715 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6717 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6719 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6720 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6721 push @$cpuFlags , 'hv_vapic';
6722 push @$cpuFlags , 'hv_time';
6724 push @$cpuFlags , 'hv_spinlocks=0xffff';
6727 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6728 push @$cpuFlags , 'hv_reset';
6729 push @$cpuFlags , 'hv_vpindex';
6730 push @$cpuFlags , 'hv_runtime';
6733 if ($winversion >= 7) {
6734 push @$cpuFlags , 'hv_relaxed';
6736 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6737 push @$cpuFlags , 'hv_synic';
6738 push @$cpuFlags , 'hv_stimer';
6743 sub windows_version
{
6746 return 0 if !$ostype;
6750 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6752 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6754 } elsif ($ostype =~ m/^win(\d+)$/) {
6761 sub resolve_dst_disk_format
{
6762 my ($storecfg, $storeid, $src_volname, $format) = @_;
6763 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6766 # if no target format is specified, use the source disk format as hint
6768 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6769 $format = qemu_img_format
($scfg, $src_volname);
6775 # test if requested format is supported - else use default
6776 my $supported = grep { $_ eq $format } @$validFormats;
6777 $format = $defFormat if !$supported;
6781 sub resolve_first_disk
{
6783 my @disks = PVE
::QemuServer
::valid_drive_names
();
6785 foreach my $ds (reverse @disks) {
6786 next if !$conf->{$ds};
6787 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6788 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6795 my ($uuid, $uuid_str);
6796 UUID
::generate
($uuid);
6797 UUID
::unparse
($uuid, $uuid_str);
6801 sub generate_smbios1_uuid
{
6802 return "uuid=".generate_uuid
();
6805 # bash completion helper
6807 sub complete_backup_archives
{
6808 my ($cmdname, $pname, $cvalue) = @_;
6810 my $cfg = PVE
::Storage
::config
();
6814 if ($cvalue =~ m/^([^:]+):/) {
6818 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6821 foreach my $id (keys %$data) {
6822 foreach my $item (@{$data->{$id}}) {
6823 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6824 push @$res, $item->{volid
} if defined($item->{volid
});
6831 my $complete_vmid_full = sub {
6834 my $idlist = vmstatus
();
6838 foreach my $id (keys %$idlist) {
6839 my $d = $idlist->{$id};
6840 if (defined($running)) {
6841 next if $d->{template
};
6842 next if $running && $d->{status
} ne 'running';
6843 next if !$running && $d->{status
} eq 'running';
6852 return &$complete_vmid_full();
6855 sub complete_vmid_stopped
{
6856 return &$complete_vmid_full(0);
6859 sub complete_vmid_running
{
6860 return &$complete_vmid_full(1);
6863 sub complete_storage
{
6865 my $cfg = PVE
::Storage
::config
();
6866 my $ids = $cfg->{ids
};
6869 foreach my $sid (keys %$ids) {
6870 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6871 next if !$ids->{$sid}->{content
}->{images
};
6881 vm_mon_cmd
($vmid, 'nbd-server-stop');