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 #no warnings 'redefine';
86 my ($controller, $vmid, $option, $value) = @_;
88 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
89 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
93 my $nodename = PVE
::INotify
::nodename
();
95 mkdir "/etc/pve/nodes/$nodename";
96 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
99 my $var_run_tmpdir = "/var/run/qemu-server";
100 mkdir $var_run_tmpdir;
102 my $lock_dir = "/var/lock/qemu-server";
105 my $pcisysfs = "/sys/bus/pci";
107 my $cpu_vendor_list = {
109 486 => 'GenuineIntel',
110 pentium
=> 'GenuineIntel',
111 pentium2
=> 'GenuineIntel',
112 pentium3
=> 'GenuineIntel',
113 coreduo
=> 'GenuineIntel',
114 core2duo
=> 'GenuineIntel',
115 Conroe
=> 'GenuineIntel',
116 Penryn
=> 'GenuineIntel',
117 Nehalem
=> 'GenuineIntel',
118 'Nehalem-IBRS' => 'GenuineIntel',
119 Westmere
=> 'GenuineIntel',
120 'Westmere-IBRS' => 'GenuineIntel',
121 SandyBridge
=> 'GenuineIntel',
122 'SandyBridge-IBRS' => 'GenuineIntel',
123 IvyBridge
=> 'GenuineIntel',
124 'IvyBridge-IBRS' => 'GenuineIntel',
125 Haswell
=> 'GenuineIntel',
126 'Haswell-IBRS' => 'GenuineIntel',
127 'Haswell-noTSX' => 'GenuineIntel',
128 'Haswell-noTSX-IBRS' => 'GenuineIntel',
129 Broadwell
=> 'GenuineIntel',
130 'Broadwell-IBRS' => 'GenuineIntel',
131 'Broadwell-noTSX' => 'GenuineIntel',
132 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
133 'Skylake-Client' => 'GenuineIntel',
134 'Skylake-Client-IBRS' => 'GenuineIntel',
135 'Skylake-Server' => 'GenuineIntel',
136 'Skylake-Server-IBRS' => 'GenuineIntel',
139 athlon
=> 'AuthenticAMD',
140 phenom
=> 'AuthenticAMD',
141 Opteron_G1
=> 'AuthenticAMD',
142 Opteron_G2
=> 'AuthenticAMD',
143 Opteron_G3
=> 'AuthenticAMD',
144 Opteron_G4
=> 'AuthenticAMD',
145 Opteron_G5
=> 'AuthenticAMD',
146 EPYC
=> 'AuthenticAMD',
147 'EPYC-IBPB' => 'AuthenticAMD',
149 # generic types, use vendor from host node
158 my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
162 description
=> "Emulated CPU type.",
164 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
169 description
=> "Do not identify as a KVM virtual machine.",
175 description
=> "List of additional CPU flags separated by ';'."
176 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
177 . " Currently supported flags: 'pcid', 'spec-ctrl'.",
178 format_description
=> '+FLAG[;-FLAG...]',
180 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
189 enum
=> [qw(i6300esb ib700)],
190 description
=> "Watchdog type to emulate.",
191 default => 'i6300esb',
196 enum
=> [qw(reset shutdown poweroff pause debug none)],
197 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
201 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
207 description
=> "Specifies whether a VM will be started during system bootup.",
213 description
=> "Automatic restart after crash (currently ignored).",
218 type
=> 'string', format
=> 'pve-hotplug-features',
219 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'.",
220 default => 'network,disk,usb',
225 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
231 description
=> "Lock/unlock the VM.",
232 enum
=> [qw(migrate backup snapshot rollback)],
237 description
=> "Limit of CPU usage.",
238 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.",
246 description
=> "CPU weight for a VM.",
247 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.",
255 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
262 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
268 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.",
276 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
277 "It should not be necessary to set it.",
278 enum
=> PVE
::Tools
::kvmkeymaplist
(),
283 type
=> 'string', format
=> 'dns-name',
284 description
=> "Set a name for the VM. Only used on the configuration web interface.",
289 description
=> "SCSI controller model",
290 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
296 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
301 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
302 description
=> "Specify guest operating system.",
303 verbose_description
=> <<EODESC,
304 Specify guest operating system. This is used to enable special
305 optimization/features for specific operating systems:
308 other;; unspecified OS
309 wxp;; Microsoft Windows XP
310 w2k;; Microsoft Windows 2000
311 w2k3;; Microsoft Windows 2003
312 w2k8;; Microsoft Windows 2008
313 wvista;; Microsoft Windows Vista
314 win7;; Microsoft Windows 7
315 win8;; Microsoft Windows 8/2012/2012r2
316 win10;; Microsoft Windows 10/2016
317 l24;; Linux 2.4 Kernel
318 l26;; Linux 2.6/3.X Kernel
319 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
325 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
326 pattern
=> '[acdn]{1,4}',
331 type
=> 'string', format
=> 'pve-qm-bootdisk',
332 description
=> "Enable booting from specified disk.",
333 pattern
=> '(ide|sata|scsi|virtio)\d+',
338 description
=> "The number of CPUs. Please use option -sockets instead.",
345 description
=> "The number of CPU sockets.",
352 description
=> "The number of cores per socket.",
359 description
=> "Enable/disable NUMA.",
365 description
=> "Enable/disable hugepages memory.",
366 enum
=> [qw(any 2 1024)],
371 description
=> "Number of hotplugged vcpus.",
378 description
=> "Enable/disable ACPI.",
384 description
=> "Enable/disable Qemu GuestAgent.",
390 description
=> "Enable/disable KVM hardware virtualization.",
396 description
=> "Enable/disable time drift fix.",
402 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
407 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
412 description
=> "Select the VGA type.",
413 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
414 " modes (>= 1280x1024x16) then you should use the options " .
415 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
416 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
417 "display sever. For win* OS you can select how many independent " .
418 "displays you want, Linux guests can add displays them self. " .
419 "You can also run without any graphic card, using a serial device" .
421 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
425 type
=> 'string', format
=> 'pve-qm-watchdog',
426 description
=> "Create a virtual hardware watchdog device.",
427 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
428 " (by a guest action), the watchdog must be periodically polled " .
429 "by an agent inside the guest or else the watchdog will reset " .
430 "the guest (or execute the respective action specified)",
435 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
436 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'.",
437 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
440 startup
=> get_standard_option
('pve-startup-order'),
444 description
=> "Enable/disable Template.",
450 description
=> "Arbitrary arguments passed to kvm.",
451 verbose_description
=> <<EODESCR,
452 Arbitrary arguments passed to kvm, for example:
454 args: -no-reboot -no-hpet
456 NOTE: this option is for experts only.
463 description
=> "Enable/disable the USB tablet device.",
464 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
465 "usually needed to allow absolute mouse positioning with VNC. " .
466 "Else the mouse runs out of sync with normal VNC clients. " .
467 "If you're running lots of console-only guests on one host, " .
468 "you may consider disabling this to save some context switches. " .
469 "This is turned off by default if you use spice (-vga=qxl).",
474 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
478 migrate_downtime
=> {
481 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
487 type
=> 'string', format
=> 'pve-qm-ide',
488 typetext
=> '<volume>',
489 description
=> "This is an alias for option -ide2",
493 description
=> "Emulated CPU type.",
497 parent
=> get_standard_option
('pve-snapshot-name', {
499 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
503 description
=> "Timestamp for snapshots.",
509 type
=> 'string', format
=> 'pve-volume-id',
510 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
512 vmstatestorage
=> get_standard_option
('pve-storage-id', {
513 description
=> "Default storage for VM state volumes/files.",
517 description
=> "Specific the Qemu machine type.",
519 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
524 description
=> "Specify SMBIOS type 1 fields.",
525 type
=> 'string', format
=> 'pve-qm-smbios1',
532 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
538 enum
=> [ qw(seabios ovmf) ],
539 description
=> "Select BIOS implementation.",
540 default => 'seabios',
544 my $confdesc_cloudinit = {
548 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.',
549 enum
=> ['configdrive2', 'nocloud'],
554 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
559 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.',
564 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.",
568 type
=> 'string', format
=> 'address-list',
569 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.",
574 format
=> 'urlencoded',
575 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
579 # what about other qemu settings ?
581 #machine => 'string',
594 ##soundhw => 'string',
596 while (my ($k, $v) = each %$confdesc) {
597 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
600 my $MAX_IDE_DISKS = 4;
601 my $MAX_SCSI_DISKS = 14;
602 my $MAX_VIRTIO_DISKS = 16;
603 my $MAX_SATA_DISKS = 6;
604 my $MAX_USB_DEVICES = 5;
606 my $MAX_UNUSED_DISKS = 8;
607 my $MAX_HOSTPCI_DEVICES = 4;
608 my $MAX_SERIAL_PORTS = 4;
609 my $MAX_PARALLEL_PORTS = 3;
615 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
616 description
=> "CPUs accessing this NUMA node.",
617 format_description
=> "id[-id];...",
621 description
=> "Amount of memory this NUMA node provides.",
626 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
627 description
=> "Host NUMA nodes to use.",
628 format_description
=> "id[-id];...",
633 enum
=> [qw(preferred bind interleave)],
634 description
=> "NUMA allocation policy.",
638 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
641 type
=> 'string', format
=> $numa_fmt,
642 description
=> "NUMA topology.",
644 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
646 for (my $i = 0; $i < $MAX_NUMA; $i++) {
647 $confdesc->{"numa$i"} = $numadesc;
650 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
651 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
652 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
653 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
655 my $net_fmt_bridge_descr = <<__EOD__;
656 Bridge to attach the network device to. The Proxmox VE standard bridge
659 If you do not specify a bridge, we create a kvm user (NATed) network
660 device, which provides DHCP and DNS services. The following addresses
667 The DHCP server assign addresses to the guest starting from 10.0.2.15.
673 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
674 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
675 format_description
=> "XX:XX:XX:XX:XX:XX",
680 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'.",
681 enum
=> $nic_model_list,
684 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
687 description
=> $net_fmt_bridge_descr,
688 format_description
=> 'bridge',
693 minimum
=> 0, maximum
=> 16,
694 description
=> 'Number of packet queues to be used on the device.',
700 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
705 minimum
=> 1, maximum
=> 4094,
706 description
=> 'VLAN tag to apply to packets on this interface.',
711 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
712 description
=> 'VLAN trunks to pass through this interface.',
713 format_description
=> 'vlanid[;vlanid...]',
718 description
=> 'Whether this interface should be protected by the firewall.',
723 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
730 type
=> 'string', format
=> $net_fmt,
731 description
=> "Specify network devices.",
734 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
739 format
=> 'pve-ipv4-config',
740 format_description
=> 'IPv4Format/CIDR',
741 description
=> 'IPv4 address in CIDR format.',
748 format_description
=> 'GatewayIPv4',
749 description
=> 'Default gateway for IPv4 traffic.',
755 format
=> 'pve-ipv6-config',
756 format_description
=> 'IPv6Format/CIDR',
757 description
=> 'IPv6 address in CIDR format.',
764 format_description
=> 'GatewayIPv6',
765 description
=> 'Default gateway for IPv6 traffic.',
770 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
773 type
=> 'string', format
=> 'pve-qm-ipconfig',
774 description
=> <<'EODESCR',
775 cloud-init: Specify IP addresses and gateways for the corresponding interface.
777 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
779 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
780 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
782 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
785 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
787 for (my $i = 0; $i < $MAX_NETS; $i++) {
788 $confdesc->{"net$i"} = $netdesc;
789 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
792 foreach my $key (keys %$confdesc_cloudinit) {
793 $confdesc->{$key} = $confdesc_cloudinit->{$key};
796 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
797 sub verify_volume_id_or_qm_path
{
798 my ($volid, $noerr) = @_;
800 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
804 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
805 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
807 return undef if $noerr;
815 my %drivedesc_base = (
816 volume
=> { alias
=> 'file' },
819 format
=> 'pve-volume-id-or-qm-path',
821 format_description
=> 'volume',
822 description
=> "The drive's backing volume.",
826 enum
=> [qw(cdrom disk)],
827 description
=> "The drive's media type.",
833 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
838 description
=> "Force the drive's physical geometry to have a specific head count.",
843 description
=> "Force the drive's physical geometry to have a specific sector count.",
848 enum
=> [qw(none lba auto)],
849 description
=> "Force disk geometry bios translation mode.",
854 description
=> "Controls qemu's snapshot mode feature."
855 . " If activated, changes made to the disk are temporary and will"
856 . " be discarded when the VM is shutdown.",
861 enum
=> [qw(none writethrough writeback unsafe directsync)],
862 description
=> "The drive's cache mode",
865 format
=> get_standard_option
('pve-qm-image-format'),
868 format
=> 'disk-size',
869 format_description
=> 'DiskSize',
870 description
=> "Disk size. This is purely informational and has no effect.",
875 description
=> "Whether the drive should be included when making backups.",
880 description
=> 'Whether the drive should considered for replication jobs.',
886 enum
=> [qw(ignore report stop)],
887 description
=> 'Read error action.',
892 enum
=> [qw(enospc ignore report stop)],
893 description
=> 'Write error action.',
898 enum
=> [qw(native threads)],
899 description
=> 'AIO type to use.',
904 enum
=> [qw(ignore on)],
905 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
910 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
915 format
=> 'urlencoded',
916 format_description
=> 'serial',
917 maxLength
=> 20*3, # *3 since it's %xx url enoded
918 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
923 description
=> 'Mark this locally-managed volume as available on all nodes',
924 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!",
930 my %iothread_fmt = ( iothread
=> {
932 description
=> "Whether to use iothreads for this drive",
939 format
=> 'urlencoded',
940 format_description
=> 'model',
941 maxLength
=> 40*3, # *3 since it's %xx url enoded
942 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
950 description
=> "Number of queues.",
956 my %scsiblock_fmt = (
959 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",
965 my $add_throttle_desc = sub {
966 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
969 format_description
=> $unit,
970 description
=> "Maximum $what in $longunit.",
973 $d->{minimum
} = $minimum if defined($minimum);
974 $drivedesc_base{$key} = $d;
976 # throughput: (leaky bucket)
977 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
978 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
979 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
980 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
981 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
982 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
983 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
984 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
985 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
987 # pools: (pool of IO before throttling starts taking effect)
988 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
989 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
990 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
991 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
992 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
993 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
996 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
997 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
998 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
999 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1000 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1001 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1004 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1005 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1006 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1007 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1013 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1017 type
=> 'string', format
=> $ide_fmt,
1018 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1020 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1030 type
=> 'string', format
=> $scsi_fmt,
1031 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1033 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1040 type
=> 'string', format
=> $sata_fmt,
1041 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1043 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1051 type
=> 'string', format
=> $virtio_fmt,
1052 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1054 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1056 my $alldrive_fmt = {
1065 volume
=> { alias
=> 'file' },
1068 format
=> 'pve-volume-id-or-qm-path',
1070 format_description
=> 'volume',
1071 description
=> "The drive's backing volume.",
1073 format
=> get_standard_option
('pve-qm-image-format'),
1076 format
=> 'disk-size',
1077 format_description
=> 'DiskSize',
1078 description
=> "Disk size. This is purely informational and has no effect.",
1083 my $efidisk_desc = {
1085 type
=> 'string', format
=> $efidisk_fmt,
1086 description
=> "Configure a Disk for storing EFI vars",
1089 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1094 type
=> 'string', format
=> 'pve-qm-usb-device',
1095 format_description
=> 'HOSTUSBDEVICE|spice',
1096 description
=> <<EODESCR,
1097 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1099 'bus-port(.port)*' (decimal numbers) or
1100 'vendor_id:product_id' (hexadeciaml numbers) or
1103 You can use the 'lsusb -t' command to list existing usb devices.
1105 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1107 The value 'spice' can be used to add a usb redirection devices for spice.
1113 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).",
1120 type
=> 'string', format
=> $usb_fmt,
1121 description
=> "Configure an USB device (n is 0 to 4).",
1123 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1125 # NOTE: the match-groups of this regex are used in parse_hostpci
1126 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1131 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1132 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1133 description
=> <<EODESCR,
1134 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1135 of PCI virtual functions of the host. HOSTPCIID syntax is:
1137 'bus:dev.func' (hexadecimal numbers)
1139 You can us the 'lspci' command to list existing PCI devices.
1144 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1150 pattern
=> '[^,;]+',
1151 format_description
=> 'string',
1152 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1157 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1163 description
=> "Enable vfio-vga device support.",
1168 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1172 type
=> 'string', format
=> 'pve-qm-hostpci',
1173 description
=> "Map host PCI devices into guest.",
1174 verbose_description
=> <<EODESCR,
1175 Map host PCI devices into guest.
1177 NOTE: This option allows direct access to host hardware. So it is no longer
1178 possible to migrate such machines - use with special care.
1180 CAUTION: Experimental! User reported problems with this option.
1183 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1188 pattern
=> '(/dev/.+|socket)',
1189 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1190 verbose_description
=> <<EODESCR,
1191 Create a serial device inside the VM (n is 0 to 3), and pass through a
1192 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1193 host side (use 'qm terminal' to open a terminal connection).
1195 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1197 CAUTION: Experimental! User reported problems with this option.
1204 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1205 description
=> "Map host parallel devices (n is 0 to 2).",
1206 verbose_description
=> <<EODESCR,
1207 Map host parallel devices (n is 0 to 2).
1209 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1211 CAUTION: Experimental! User reported problems with this option.
1215 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1216 $confdesc->{"parallel$i"} = $paralleldesc;
1219 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1220 $confdesc->{"serial$i"} = $serialdesc;
1223 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1224 $confdesc->{"hostpci$i"} = $hostpcidesc;
1227 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1228 $drivename_hash->{"ide$i"} = 1;
1229 $confdesc->{"ide$i"} = $idedesc;
1232 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1233 $drivename_hash->{"sata$i"} = 1;
1234 $confdesc->{"sata$i"} = $satadesc;
1237 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1238 $drivename_hash->{"scsi$i"} = 1;
1239 $confdesc->{"scsi$i"} = $scsidesc ;
1242 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1243 $drivename_hash->{"virtio$i"} = 1;
1244 $confdesc->{"virtio$i"} = $virtiodesc;
1247 $drivename_hash->{efidisk0
} = 1;
1248 $confdesc->{efidisk0
} = $efidisk_desc;
1250 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1251 $confdesc->{"usb$i"} = $usbdesc;
1256 type
=> 'string', format
=> 'pve-volume-id',
1257 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1260 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1261 $confdesc->{"unused$i"} = $unuseddesc;
1264 my $kvm_api_version = 0;
1268 return $kvm_api_version if $kvm_api_version;
1270 my $fh = IO
::File-
>new("</dev/kvm") ||
1273 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1274 $kvm_api_version = $v;
1279 return $kvm_api_version;
1282 my $kvm_user_version;
1284 sub kvm_user_version
{
1286 return $kvm_user_version if $kvm_user_version;
1288 $kvm_user_version = 'unknown';
1292 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1293 $kvm_user_version = $2;
1297 eval { run_command
("kvm -version", outfunc
=> $code); };
1300 return $kvm_user_version;
1304 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1306 sub valid_drive_names
{
1307 # order is important - used to autoselect boot disk
1308 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1309 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1310 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1311 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1315 sub is_valid_drivename
{
1318 return defined($drivename_hash->{$dev});
1323 return defined($confdesc->{$key});
1327 return $nic_model_list;
1330 sub os_list_description
{
1334 wxp
=> 'Windows XP',
1335 w2k
=> 'Windows 2000',
1336 w2k3
=>, 'Windows 2003',
1337 w2k8
=> 'Windows 2008',
1338 wvista
=> 'Windows Vista',
1339 win7
=> 'Windows 7',
1340 win8
=> 'Windows 8/2012',
1341 win10
=> 'Windows 10/2016',
1349 sub get_cdrom_path
{
1351 return $cdrom_path if $cdrom_path;
1353 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1354 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1355 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1359 my ($storecfg, $vmid, $cdrom) = @_;
1361 if ($cdrom eq 'cdrom') {
1362 return get_cdrom_path
();
1363 } elsif ($cdrom eq 'none') {
1365 } elsif ($cdrom =~ m
|^/|) {
1368 return PVE
::Storage
::path
($storecfg, $cdrom);
1372 # try to convert old style file names to volume IDs
1373 sub filename_to_volume_id
{
1374 my ($vmid, $file, $media) = @_;
1376 if (!($file eq 'none' || $file eq 'cdrom' ||
1377 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1379 return undef if $file =~ m
|/|;
1381 if ($media && $media eq 'cdrom') {
1382 $file = "local:iso/$file";
1384 $file = "local:$vmid/$file";
1391 sub verify_media_type
{
1392 my ($opt, $vtype, $media) = @_;
1397 if ($media eq 'disk') {
1399 } elsif ($media eq 'cdrom') {
1402 die "internal error";
1405 return if ($vtype eq $etype);
1407 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1410 sub cleanup_drive_path
{
1411 my ($opt, $storecfg, $drive) = @_;
1413 # try to convert filesystem paths to volume IDs
1415 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1416 ($drive->{file
} !~ m
|^/dev/.+|) &&
1417 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1418 ($drive->{file
} !~ m/^\d+$/)) {
1419 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1420 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1421 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1422 verify_media_type
($opt, $vtype, $drive->{media
});
1423 $drive->{file
} = $volid;
1426 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1429 sub parse_hotplug_features
{
1434 return $res if $data eq '0';
1436 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1438 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1439 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1442 die "invalid hotplug feature '$feature'\n";
1448 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1449 sub pve_verify_hotplug_features
{
1450 my ($value, $noerr) = @_;
1452 return $value if parse_hotplug_features
($value);
1454 return undef if $noerr;
1456 die "unable to parse hotplug option\n";
1459 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1460 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1461 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1462 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1463 # [,iothread=on][,serial=serial][,model=model]
1466 my ($key, $data) = @_;
1468 my ($interface, $index);
1470 if ($key =~ m/^([^\d]+)(\d+)$/) {
1477 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1478 : $confdesc->{$key}->{format
};
1480 warn "invalid drive key: $key\n";
1483 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1484 return undef if !$res;
1485 $res->{interface
} = $interface;
1486 $res->{index} = $index;
1489 foreach my $opt (qw(bps bps_rd bps_wr)) {
1490 if (my $bps = defined(delete $res->{$opt})) {
1491 if (defined($res->{"m$opt"})) {
1492 warn "both $opt and m$opt specified\n";
1496 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1500 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1501 for my $requirement (
1502 [mbps_max
=> 'mbps'],
1503 [mbps_rd_max
=> 'mbps_rd'],
1504 [mbps_wr_max
=> 'mbps_wr'],
1505 [miops_max
=> 'miops'],
1506 [miops_rd_max
=> 'miops_rd'],
1507 [miops_wr_max
=> 'miops_wr'],
1508 [bps_max_length
=> 'mbps_max'],
1509 [bps_rd_max_length
=> 'mbps_rd_max'],
1510 [bps_wr_max_length
=> 'mbps_wr_max'],
1511 [iops_max_length
=> 'iops_max'],
1512 [iops_rd_max_length
=> 'iops_rd_max'],
1513 [iops_wr_max_length
=> 'iops_wr_max']) {
1514 my ($option, $requires) = @$requirement;
1515 if ($res->{$option} && !$res->{$requires}) {
1516 warn "$option requires $requires\n";
1521 return undef if $error;
1523 return undef if $res->{mbps_rd
} && $res->{mbps
};
1524 return undef if $res->{mbps_wr
} && $res->{mbps
};
1525 return undef if $res->{iops_rd
} && $res->{iops
};
1526 return undef if $res->{iops_wr
} && $res->{iops
};
1528 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1529 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1530 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1531 return undef if $res->{interface
} eq 'virtio';
1534 if (my $size = $res->{size
}) {
1535 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1542 my ($vmid, $drive) = @_;
1543 my $data = { %$drive };
1544 delete $data->{$_} for qw(index interface);
1545 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1549 my($fh, $noerr) = @_;
1552 my $SG_GET_VERSION_NUM = 0x2282;
1554 my $versionbuf = "\x00" x
8;
1555 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1557 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1560 my $version = unpack("I", $versionbuf);
1561 if ($version < 30000) {
1562 die "scsi generic interface too old\n" if !$noerr;
1566 my $buf = "\x00" x
36;
1567 my $sensebuf = "\x00" x
8;
1568 my $cmd = pack("C x3 C x1", 0x12, 36);
1570 # see /usr/include/scsi/sg.h
1571 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";
1573 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1574 length($sensebuf), 0, length($buf), $buf,
1575 $cmd, $sensebuf, 6000);
1577 $ret = ioctl($fh, $SG_IO, $packet);
1579 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1583 my @res = unpack($sg_io_hdr_t, $packet);
1584 if ($res[17] || $res[18]) {
1585 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1590 (my $byte0, my $byte1, $res->{vendor
},
1591 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1593 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1594 $res->{type
} = $byte0 & 31;
1602 my $fh = IO
::File-
>new("+<$path") || return undef;
1603 my $res = scsi_inquiry
($fh, 1);
1609 sub machine_type_is_q35
{
1612 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1615 sub print_tabletdevice_full
{
1618 my $q35 = machine_type_is_q35
($conf);
1620 # we use uhci for old VMs because tablet driver was buggy in older qemu
1621 my $usbbus = $q35 ?
"ehci" : "uhci";
1623 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1626 sub print_drivedevice_full
{
1627 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1632 if ($drive->{interface
} eq 'virtio') {
1633 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1634 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1635 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1636 } elsif ($drive->{interface
} eq 'scsi') {
1638 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1639 my $unit = $drive->{index} % $maxdev;
1640 my $devicetype = 'hd';
1642 if (drive_is_cdrom
($drive)) {
1645 if ($drive->{file
} =~ m
|^/|) {
1646 $path = $drive->{file
};
1647 if (my $info = path_is_scsi
($path)) {
1648 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1649 $devicetype = 'block';
1650 } elsif ($info->{type
} == 1) { # tape
1651 $devicetype = 'generic';
1655 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1658 if($path =~ m/^iscsi\:\/\
//){
1659 $devicetype = 'generic';
1663 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1664 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1666 $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}";
1669 } elsif ($drive->{interface
} eq 'ide'){
1671 my $controller = int($drive->{index} / $maxdev);
1672 my $unit = $drive->{index} % $maxdev;
1673 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1675 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1676 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1677 $model = URI
::Escape
::uri_unescape
($model);
1678 $device .= ",model=$model";
1680 } elsif ($drive->{interface
} eq 'sata'){
1681 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1682 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1683 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1684 } elsif ($drive->{interface
} eq 'usb') {
1686 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1688 die "unsupported interface type";
1691 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1693 if (my $serial = $drive->{serial
}) {
1694 $serial = URI
::Escape
::uri_unescape
($serial);
1695 $device .= ",serial=$serial";
1702 sub get_initiator_name
{
1705 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1706 while (defined(my $line = <$fh>)) {
1707 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1716 sub print_drive_full
{
1717 my ($storecfg, $vmid, $drive) = @_;
1720 my $volid = $drive->{file
};
1723 if (drive_is_cdrom
($drive)) {
1724 $path = get_iso_path
($storecfg, $vmid, $volid);
1726 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1728 $path = PVE
::Storage
::path
($storecfg, $volid);
1729 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1730 $format = qemu_img_format
($scfg, $volname);
1738 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1739 foreach my $o (@qemu_drive_options) {
1740 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1743 # snapshot only accepts on|off
1744 if (defined($drive->{snapshot
})) {
1745 my $v = $drive->{snapshot
} ?
'on' : 'off';
1746 $opts .= ",snapshot=$v";
1749 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1750 my ($dir, $qmpname) = @$type;
1751 if (my $v = $drive->{"mbps$dir"}) {
1752 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1754 if (my $v = $drive->{"mbps${dir}_max"}) {
1755 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1757 if (my $v = $drive->{"bps${dir}_max_length"}) {
1758 $opts .= ",throttling.bps$qmpname-max-length=$v";
1760 if (my $v = $drive->{"iops${dir}"}) {
1761 $opts .= ",throttling.iops$qmpname=$v";
1763 if (my $v = $drive->{"iops${dir}_max"}) {
1764 $opts .= ",throttling.iops$qmpname-max=$v";
1766 if (my $v = $drive->{"iops${dir}_max_length"}) {
1767 $opts .= ",throttling.iops$qmpname-max-length=$v";
1771 $opts .= ",format=$format" if $format && !$drive->{format
};
1773 my $cache_direct = 0;
1775 if (my $cache = $drive->{cache
}) {
1776 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1777 } elsif (!drive_is_cdrom
($drive)) {
1778 $opts .= ",cache=none";
1782 # aio native works only with O_DIRECT
1783 if (!$drive->{aio
}) {
1785 $opts .= ",aio=native";
1787 $opts .= ",aio=threads";
1791 if (!drive_is_cdrom
($drive)) {
1793 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1794 $detectzeroes = 'off';
1795 } elsif ($drive->{discard
}) {
1796 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1798 # This used to be our default with discard not being specified:
1799 $detectzeroes = 'on';
1801 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1804 my $pathinfo = $path ?
"file=$path," : '';
1806 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1809 sub print_netdevice_full
{
1810 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1812 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1814 my $device = $net->{model
};
1815 if ($net->{model
} eq 'virtio') {
1816 $device = 'virtio-net-pci';
1819 my $pciaddr = print_pci_addr
("$netid", $bridges);
1820 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1821 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1822 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1823 my $vectors = $net->{queues
} * 2 + 2;
1824 $tmpstr .= ",vectors=$vectors,mq=on";
1826 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1828 if ($use_old_bios_files) {
1830 if ($device eq 'virtio-net-pci') {
1831 $romfile = 'pxe-virtio.rom';
1832 } elsif ($device eq 'e1000') {
1833 $romfile = 'pxe-e1000.rom';
1834 } elsif ($device eq 'ne2k') {
1835 $romfile = 'pxe-ne2k_pci.rom';
1836 } elsif ($device eq 'pcnet') {
1837 $romfile = 'pxe-pcnet.rom';
1838 } elsif ($device eq 'rtl8139') {
1839 $romfile = 'pxe-rtl8139.rom';
1841 $tmpstr .= ",romfile=$romfile" if $romfile;
1847 sub print_netdev_full
{
1848 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1851 if ($netid =~ m/^net(\d+)$/) {
1855 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1857 my $ifname = "tap${vmid}i$i";
1859 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1860 die "interface name '$ifname' is too long (max 15 character)\n"
1861 if length($ifname) >= 16;
1863 my $vhostparam = '';
1864 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1866 my $vmname = $conf->{name
} || "vm$vmid";
1869 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1871 if ($net->{bridge
}) {
1872 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1874 $netdev = "type=user,id=$netid,hostname=$vmname";
1877 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1883 sub print_cpu_device
{
1884 my ($conf, $id) = @_;
1886 my $kvm = $conf->{kvm
} // 1;
1887 my $cpu = $kvm ?
"kvm64" : "qemu64";
1888 if (my $cputype = $conf->{cpu
}) {
1889 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1890 or die "Cannot parse cpu description: $cputype\n";
1891 $cpu = $cpuconf->{cputype
};
1894 my $cores = $conf->{cores
} || 1;
1896 my $current_core = ($id - 1) % $cores;
1897 my $current_socket = int(($id - 1 - $current_core)/$cores);
1899 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1902 sub drive_is_cloudinit
{
1904 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1907 sub drive_is_cdrom
{
1908 my ($drive, $exclude_cloudinit) = @_;
1910 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1912 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1916 sub parse_number_sets
{
1919 foreach my $part (split(/;/, $set)) {
1920 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1921 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1922 push @$res, [ $1, $2 ];
1924 die "invalid range: $part\n";
1933 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1934 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1935 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1942 return undef if !$value;
1944 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1946 my @idlist = split(/;/, $res->{host
});
1947 delete $res->{host
};
1948 foreach my $id (@idlist) {
1949 if ($id =~ /^$PCIRE$/) {
1951 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1953 my $pcidevices = lspci
($1);
1954 $res->{pciid
} = $pcidevices->{$1};
1957 # should have been caught by parse_property_string already
1958 die "failed to parse PCI id: $id\n";
1964 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1968 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1973 if (!defined($res->{macaddr
})) {
1974 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1975 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1980 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1981 sub parse_ipconfig
{
1984 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1990 if ($res->{gw
} && !$res->{ip
}) {
1991 warn 'gateway specified without specifying an IP address';
1994 if ($res->{gw6
} && !$res->{ip6
}) {
1995 warn 'IPv6 gateway specified without specifying an IPv6 address';
1998 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1999 warn 'gateway specified together with DHCP';
2002 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2004 warn "IPv6 gateway specified together with $res->{ip6} address";
2008 if (!$res->{ip
} && !$res->{ip6
}) {
2009 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2018 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2021 sub add_random_macs
{
2022 my ($settings) = @_;
2024 foreach my $opt (keys %$settings) {
2025 next if $opt !~ m/^net(\d+)$/;
2026 my $net = parse_net
($settings->{$opt});
2028 $settings->{$opt} = print_net
($net);
2032 sub vm_is_volid_owner
{
2033 my ($storecfg, $vmid, $volid) = @_;
2035 if ($volid !~ m
|^/|) {
2037 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2038 if ($owner && ($owner == $vmid)) {
2046 sub split_flagged_list
{
2047 my $text = shift || '';
2048 $text =~ s/[,;]/ /g;
2050 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2053 sub join_flagged_list
{
2054 my ($how, $lst) = @_;
2055 join $how, map { $lst->{$_} . $_ } keys %$lst;
2058 sub vmconfig_delete_pending_option
{
2059 my ($conf, $key, $force) = @_;
2061 delete $conf->{pending
}->{$key};
2062 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2063 $pending_delete_hash->{$key} = $force ?
'!' : '';
2064 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2067 sub vmconfig_undelete_pending_option
{
2068 my ($conf, $key) = @_;
2070 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2071 delete $pending_delete_hash->{$key};
2073 if (%$pending_delete_hash) {
2074 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2076 delete $conf->{pending
}->{delete};
2080 sub vmconfig_register_unused_drive
{
2081 my ($storecfg, $vmid, $conf, $drive) = @_;
2083 if (drive_is_cloudinit
($drive)) {
2084 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2086 } elsif (!drive_is_cdrom
($drive)) {
2087 my $volid = $drive->{file
};
2088 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2089 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2094 sub vmconfig_cleanup_pending
{
2097 # remove pending changes when nothing changed
2099 foreach my $opt (keys %{$conf->{pending
}}) {
2100 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2102 delete $conf->{pending
}->{$opt};
2106 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2107 my $pending_delete_hash = {};
2108 while (my ($opt, $force) = each %$current_delete_hash) {
2109 if (defined($conf->{$opt})) {
2110 $pending_delete_hash->{$opt} = $force;
2116 if (%$pending_delete_hash) {
2117 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2119 delete $conf->{pending
}->{delete};
2125 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2129 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2130 format_description
=> 'UUID',
2131 description
=> "Set SMBIOS1 UUID.",
2137 format_description
=> 'string',
2138 description
=> "Set SMBIOS1 version.",
2144 format_description
=> 'string',
2145 description
=> "Set SMBIOS1 serial number.",
2151 format_description
=> 'string',
2152 description
=> "Set SMBIOS1 manufacturer.",
2158 format_description
=> 'string',
2159 description
=> "Set SMBIOS1 product ID.",
2165 format_description
=> 'string',
2166 description
=> "Set SMBIOS1 SKU string.",
2172 format_description
=> 'string',
2173 description
=> "Set SMBIOS1 family string.",
2181 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2188 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2191 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2193 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2194 sub verify_bootdisk
{
2195 my ($value, $noerr) = @_;
2197 return $value if is_valid_drivename
($value);
2199 return undef if $noerr;
2201 die "invalid boot disk '$value'\n";
2204 sub parse_watchdog
{
2207 return undef if !$value;
2209 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2214 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2215 sub verify_usb_device
{
2216 my ($value, $noerr) = @_;
2218 return $value if parse_usb_device
($value);
2220 return undef if $noerr;
2222 die "unable to parse usb device\n";
2225 # add JSON properties for create and set function
2226 sub json_config_properties
{
2229 foreach my $opt (keys %$confdesc) {
2230 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2231 $prop->{$opt} = $confdesc->{$opt};
2237 # return copy of $confdesc_cloudinit to generate documentation
2238 sub cloudinit_config_properties
{
2240 return dclone
($confdesc_cloudinit);
2244 my ($key, $value) = @_;
2246 die "unknown setting '$key'\n" if !$confdesc->{$key};
2248 my $type = $confdesc->{$key}->{type
};
2250 if (!defined($value)) {
2251 die "got undefined value\n";
2254 if ($value =~ m/[\n\r]/) {
2255 die "property contains a line feed\n";
2258 if ($type eq 'boolean') {
2259 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2260 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2261 die "type check ('boolean') failed - got '$value'\n";
2262 } elsif ($type eq 'integer') {
2263 return int($1) if $value =~ m/^(\d+)$/;
2264 die "type check ('integer') failed - got '$value'\n";
2265 } elsif ($type eq 'number') {
2266 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2267 die "type check ('number') failed - got '$value'\n";
2268 } elsif ($type eq 'string') {
2269 if (my $fmt = $confdesc->{$key}->{format
}) {
2270 PVE
::JSONSchema
::check_format
($fmt, $value);
2273 $value =~ s/^\"(.*)\"$/$1/;
2276 die "internal error"
2280 sub check_iommu_support
{
2281 #fixme : need to check IOMMU support
2282 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2292 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2293 utime undef, undef, $conf;
2297 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2299 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2301 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2303 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2305 if ($conf->{template
}) {
2306 # check if any base image is still used by a linked clone
2307 foreach_drive
($conf, sub {
2308 my ($ds, $drive) = @_;
2310 return if drive_is_cdrom
($drive);
2312 my $volid = $drive->{file
};
2314 return if !$volid || $volid =~ m
|^/|;
2316 die "base volume '$volid' is still in use by linked cloned\n"
2317 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2322 # only remove disks owned by this VM
2323 foreach_drive
($conf, sub {
2324 my ($ds, $drive) = @_;
2326 return if drive_is_cdrom
($drive, 1);
2328 my $volid = $drive->{file
};
2330 return if !$volid || $volid =~ m
|^/|;
2332 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2333 return if !$path || !$owner || ($owner != $vmid);
2336 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2338 warn "Could not remove disk '$volid', check manually: $@" if $@;
2342 if ($keep_empty_config) {
2343 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2348 # also remove unused disk
2350 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2353 PVE
::Storage
::foreach_volid
($dl, sub {
2354 my ($volid, $sid, $volname, $d) = @_;
2355 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2364 sub parse_vm_config
{
2365 my ($filename, $raw) = @_;
2367 return undef if !defined($raw);
2370 digest
=> Digest
::SHA
::sha1_hex
($raw),
2375 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2376 || die "got strange filename '$filename'";
2384 my @lines = split(/\n/, $raw);
2385 foreach my $line (@lines) {
2386 next if $line =~ m/^\s*$/;
2388 if ($line =~ m/^\[PENDING\]\s*$/i) {
2389 $section = 'pending';
2390 if (defined($descr)) {
2392 $conf->{description
} = $descr;
2395 $conf = $res->{$section} = {};
2398 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2400 if (defined($descr)) {
2402 $conf->{description
} = $descr;
2405 $conf = $res->{snapshots
}->{$section} = {};
2409 if ($line =~ m/^\#(.*)\s*$/) {
2410 $descr = '' if !defined($descr);
2411 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2415 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2416 $descr = '' if !defined($descr);
2417 $descr .= PVE
::Tools
::decode_text
($2);
2418 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2419 $conf->{snapstate
} = $1;
2420 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2423 $conf->{$key} = $value;
2424 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2426 if ($section eq 'pending') {
2427 $conf->{delete} = $value; # we parse this later
2429 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2431 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2434 eval { $value = check_type
($key, $value); };
2436 warn "vm $vmid - unable to parse value of '$key' - $@";
2438 $key = 'ide2' if $key eq 'cdrom';
2439 my $fmt = $confdesc->{$key}->{format
};
2440 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2441 my $v = parse_drive
($key, $value);
2442 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2443 $v->{file
} = $volid;
2444 $value = print_drive
($vmid, $v);
2446 warn "vm $vmid - unable to parse value of '$key'\n";
2451 $conf->{$key} = $value;
2456 if (defined($descr)) {
2458 $conf->{description
} = $descr;
2460 delete $res->{snapstate
}; # just to be sure
2465 sub write_vm_config
{
2466 my ($filename, $conf) = @_;
2468 delete $conf->{snapstate
}; # just to be sure
2470 if ($conf->{cdrom
}) {
2471 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2472 $conf->{ide2
} = $conf->{cdrom
};
2473 delete $conf->{cdrom
};
2476 # we do not use 'smp' any longer
2477 if ($conf->{sockets
}) {
2478 delete $conf->{smp
};
2479 } elsif ($conf->{smp
}) {
2480 $conf->{sockets
} = $conf->{smp
};
2481 delete $conf->{cores
};
2482 delete $conf->{smp
};
2485 my $used_volids = {};
2487 my $cleanup_config = sub {
2488 my ($cref, $pending, $snapname) = @_;
2490 foreach my $key (keys %$cref) {
2491 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2492 $key eq 'snapstate' || $key eq 'pending';
2493 my $value = $cref->{$key};
2494 if ($key eq 'delete') {
2495 die "propertry 'delete' is only allowed in [PENDING]\n"
2497 # fixme: check syntax?
2500 eval { $value = check_type
($key, $value); };
2501 die "unable to parse value of '$key' - $@" if $@;
2503 $cref->{$key} = $value;
2505 if (!$snapname && is_valid_drivename
($key)) {
2506 my $drive = parse_drive
($key, $value);
2507 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2512 &$cleanup_config($conf);
2514 &$cleanup_config($conf->{pending
}, 1);
2516 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2517 die "internal error" if $snapname eq 'pending';
2518 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2521 # remove 'unusedX' settings if we re-add a volume
2522 foreach my $key (keys %$conf) {
2523 my $value = $conf->{$key};
2524 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2525 delete $conf->{$key};
2529 my $generate_raw_config = sub {
2530 my ($conf, $pending) = @_;
2534 # add description as comment to top of file
2535 if (defined(my $descr = $conf->{description
})) {
2537 foreach my $cl (split(/\n/, $descr)) {
2538 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2541 $raw .= "#\n" if $pending;
2545 foreach my $key (sort keys %$conf) {
2546 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2547 $raw .= "$key: $conf->{$key}\n";
2552 my $raw = &$generate_raw_config($conf);
2554 if (scalar(keys %{$conf->{pending
}})){
2555 $raw .= "\n[PENDING]\n";
2556 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2559 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2560 $raw .= "\n[$snapname]\n";
2561 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2571 # we use static defaults from our JSON schema configuration
2572 foreach my $key (keys %$confdesc) {
2573 if (defined(my $default = $confdesc->{$key}->{default})) {
2574 $res->{$key} = $default;
2582 my $vmlist = PVE
::Cluster
::get_vmlist
();
2584 return $res if !$vmlist || !$vmlist->{ids
};
2585 my $ids = $vmlist->{ids
};
2587 foreach my $vmid (keys %$ids) {
2588 my $d = $ids->{$vmid};
2589 next if !$d->{node
} || $d->{node
} ne $nodename;
2590 next if !$d->{type
} || $d->{type
} ne 'qemu';
2591 $res->{$vmid}->{exists} = 1;
2596 # test if VM uses local resources (to prevent migration)
2597 sub check_local_resources
{
2598 my ($conf, $noerr) = @_;
2602 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2603 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2605 foreach my $k (keys %$conf) {
2606 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2607 # sockets are safe: they will recreated be on the target side post-migrate
2608 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2609 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2612 die "VM uses local resources\n" if $loc_res && !$noerr;
2617 # check if used storages are available on all nodes (use by migrate)
2618 sub check_storage_availability
{
2619 my ($storecfg, $conf, $node) = @_;
2621 foreach_drive
($conf, sub {
2622 my ($ds, $drive) = @_;
2624 my $volid = $drive->{file
};
2627 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2630 # check if storage is available on both nodes
2631 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2632 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2636 # list nodes where all VM images are available (used by has_feature API)
2638 my ($conf, $storecfg) = @_;
2640 my $nodelist = PVE
::Cluster
::get_nodelist
();
2641 my $nodehash = { map { $_ => 1 } @$nodelist };
2642 my $nodename = PVE
::INotify
::nodename
();
2644 foreach_drive
($conf, sub {
2645 my ($ds, $drive) = @_;
2647 my $volid = $drive->{file
};
2650 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2652 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2653 if ($scfg->{disable
}) {
2655 } elsif (my $avail = $scfg->{nodes
}) {
2656 foreach my $node (keys %$nodehash) {
2657 delete $nodehash->{$node} if !$avail->{$node};
2659 } elsif (!$scfg->{shared
}) {
2660 foreach my $node (keys %$nodehash) {
2661 delete $nodehash->{$node} if $node ne $nodename
2671 my ($pidfile, $pid) = @_;
2673 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2677 return undef if !$line;
2678 my @param = split(/\0/, $line);
2680 my $cmd = $param[0];
2681 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2683 for (my $i = 0; $i < scalar (@param); $i++) {
2686 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2687 my $p = $param[$i+1];
2688 return 1 if $p && ($p eq $pidfile);
2697 my ($vmid, $nocheck, $node) = @_;
2699 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2701 die "unable to find configuration file for VM $vmid - no such machine\n"
2702 if !$nocheck && ! -f
$filename;
2704 my $pidfile = pidfile_name
($vmid);
2706 if (my $fd = IO
::File-
>new("<$pidfile")) {
2711 my $mtime = $st->mtime;
2712 if ($mtime > time()) {
2713 warn "file '$filename' modified in future\n";
2716 if ($line =~ m/^(\d+)$/) {
2718 if (check_cmdline
($pidfile, $pid)) {
2719 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2731 my $vzlist = config_list
();
2733 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2735 while (defined(my $de = $fd->read)) {
2736 next if $de !~ m/^(\d+)\.pid$/;
2738 next if !defined($vzlist->{$vmid});
2739 if (my $pid = check_running
($vmid)) {
2740 $vzlist->{$vmid}->{pid
} = $pid;
2748 my ($storecfg, $conf) = @_;
2750 my $bootdisk = $conf->{bootdisk
};
2751 return undef if !$bootdisk;
2752 return undef if !is_valid_drivename
($bootdisk);
2754 return undef if !$conf->{$bootdisk};
2756 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2757 return undef if !defined($drive);
2759 return undef if drive_is_cdrom
($drive);
2761 my $volid = $drive->{file
};
2762 return undef if !$volid;
2764 return $drive->{size
};
2767 my $last_proc_pid_stat;
2769 # get VM status information
2770 # This must be fast and should not block ($full == false)
2771 # We only query KVM using QMP if $full == true (this can be slow)
2773 my ($opt_vmid, $full) = @_;
2777 my $storecfg = PVE
::Storage
::config
();
2779 my $list = vzlist
();
2780 my $defaults = load_defaults
();
2782 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2784 my $cpucount = $cpuinfo->{cpus
} || 1;
2786 foreach my $vmid (keys %$list) {
2787 next if $opt_vmid && ($vmid ne $opt_vmid);
2789 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2790 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2793 $d->{pid
} = $list->{$vmid}->{pid
};
2795 # fixme: better status?
2796 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2798 my $size = disksize
($storecfg, $conf);
2799 if (defined($size)) {
2800 $d->{disk
} = 0; # no info available
2801 $d->{maxdisk
} = $size;
2807 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2808 * ($conf->{cores
} || $defaults->{cores
});
2809 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2810 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2812 $d->{name
} = $conf->{name
} || "VM $vmid";
2813 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2814 : $defaults->{memory
}*(1024*1024);
2816 if ($conf->{balloon
}) {
2817 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2818 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2819 : $defaults->{shares
};
2830 $d->{diskwrite
} = 0;
2832 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2834 $d->{serial
} = 1 if conf_has_serial
($conf);
2839 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2840 foreach my $dev (keys %$netdev) {
2841 next if $dev !~ m/^tap([1-9]\d*)i/;
2843 my $d = $res->{$vmid};
2846 $d->{netout
} += $netdev->{$dev}->{receive
};
2847 $d->{netin
} += $netdev->{$dev}->{transmit
};
2850 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2851 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2856 my $ctime = gettimeofday
;
2858 foreach my $vmid (keys %$list) {
2860 my $d = $res->{$vmid};
2861 my $pid = $d->{pid
};
2864 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2865 next if !$pstat; # not running
2867 my $used = $pstat->{utime} + $pstat->{stime
};
2869 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2871 if ($pstat->{vsize
}) {
2872 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2875 my $old = $last_proc_pid_stat->{$pid};
2877 $last_proc_pid_stat->{$pid} = {
2885 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2887 if ($dtime > 1000) {
2888 my $dutime = $used - $old->{used
};
2890 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2891 $last_proc_pid_stat->{$pid} = {
2897 $d->{cpu
} = $old->{cpu
};
2901 return $res if !$full;
2903 my $qmpclient = PVE
::QMPClient-
>new();
2905 my $ballooncb = sub {
2906 my ($vmid, $resp) = @_;
2908 my $info = $resp->{'return'};
2909 return if !$info->{max_mem
};
2911 my $d = $res->{$vmid};
2913 # use memory assigned to VM
2914 $d->{maxmem
} = $info->{max_mem
};
2915 $d->{balloon
} = $info->{actual
};
2917 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2918 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2919 $d->{freemem
} = $info->{free_mem
};
2922 $d->{ballooninfo
} = $info;
2925 my $blockstatscb = sub {
2926 my ($vmid, $resp) = @_;
2927 my $data = $resp->{'return'} || [];
2928 my $totalrdbytes = 0;
2929 my $totalwrbytes = 0;
2931 for my $blockstat (@$data) {
2932 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2933 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2935 $blockstat->{device
} =~ s/drive-//;
2936 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2938 $res->{$vmid}->{diskread
} = $totalrdbytes;
2939 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2942 my $statuscb = sub {
2943 my ($vmid, $resp) = @_;
2945 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2946 # this fails if ballon driver is not loaded, so this must be
2947 # the last commnand (following command are aborted if this fails).
2948 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2950 my $status = 'unknown';
2951 if (!defined($status = $resp->{'return'}->{status
})) {
2952 warn "unable to get VM status\n";
2956 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2959 foreach my $vmid (keys %$list) {
2960 next if $opt_vmid && ($vmid ne $opt_vmid);
2961 next if !$res->{$vmid}->{pid
}; # not running
2962 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2965 $qmpclient->queue_execute(undef, 2);
2967 foreach my $vmid (keys %$list) {
2968 next if $opt_vmid && ($vmid ne $opt_vmid);
2969 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2976 my ($conf, $func, @param) = @_;
2978 foreach my $ds (valid_drive_names
()) {
2979 next if !defined($conf->{$ds});
2981 my $drive = parse_drive
($ds, $conf->{$ds});
2984 &$func($ds, $drive, @param);
2989 my ($conf, $func, @param) = @_;
2993 my $test_volid = sub {
2994 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
2998 $volhash->{$volid}->{cdrom
} //= 1;
2999 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3001 $volhash->{$volid}->{replicate
} //= 0;
3002 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3004 $volhash->{$volid}->{shared
} //= 0;
3005 $volhash->{$volid}->{shared
} = 1 if $shared;
3007 $volhash->{$volid}->{referenced_in_config
} //= 0;
3008 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3010 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3011 if defined($snapname);
3014 foreach_drive
($conf, sub {
3015 my ($ds, $drive) = @_;
3016 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3019 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3020 my $snap = $conf->{snapshots
}->{$snapname};
3021 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3022 foreach_drive
($snap, sub {
3023 my ($ds, $drive) = @_;
3024 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3028 foreach my $volid (keys %$volhash) {
3029 &$func($volid, $volhash->{$volid}, @param);
3033 sub conf_has_serial
{
3036 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3037 if ($conf->{"serial$i"}) {
3045 sub vga_conf_has_spice
{
3048 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3053 sub config_to_command
{
3054 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3057 my $globalFlags = [];
3058 my $machineFlags = [];
3064 my $kvmver = kvm_user_version
();
3065 my $vernum = 0; # unknown
3066 my $ostype = $conf->{ostype
};
3067 my $winversion = windows_version
($ostype);
3068 my $kvm = $conf->{kvm
} // 1;
3070 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3072 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3073 $vernum = $1*1000000+$2*1000;
3074 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3075 $vernum = $1*1000000+$2*1000+$3;
3078 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3080 my $have_ovz = -f
'/proc/vz/vestat';
3082 my $q35 = machine_type_is_q35
($conf);
3083 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3084 my $machine_type = $forcemachine || $conf->{machine
};
3085 my $use_old_bios_files = undef;
3086 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3088 my $cpuunits = defined($conf->{cpuunits
}) ?
3089 $conf->{cpuunits
} : $defaults->{cpuunits
};
3091 push @$cmd, '/usr/bin/kvm';
3093 push @$cmd, '-id', $vmid;
3095 my $vmname = $conf->{name
} || "vm$vmid";
3097 push @$cmd, '-name', $vmname;
3101 my $qmpsocket = qmp_socket
($vmid);
3102 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3103 push @$cmd, '-mon', "chardev=qmp,mode=control";
3106 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3108 push @$cmd, '-daemonize';
3110 if ($conf->{smbios1
}) {
3111 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3114 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3115 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3119 if (my $efidisk = $conf->{efidisk0
}) {
3120 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3121 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3122 $format = $d->{format
};
3124 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3125 if (!defined($format)) {
3126 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3127 $format = qemu_img_format
($scfg, $volname);
3131 die "efidisk format must be specified\n"
3132 if !defined($format);
3135 warn "no efidisk configured! Using temporary efivars disk.\n";
3136 $path = "/tmp/$vmid-ovmf.fd";
3137 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3141 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3142 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3146 # add usb controllers
3147 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3148 push @$devices, @usbcontrollers if @usbcontrollers;
3149 my $vga = $conf->{vga
};
3151 my $qxlnum = vga_conf_has_spice
($vga);
3152 $vga = 'qxl' if $qxlnum;
3155 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3156 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3158 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3162 # enable absolute mouse coordinates (needed by vnc)
3164 if (defined($conf->{tablet
})) {
3165 $tablet = $conf->{tablet
};
3167 $tablet = $defaults->{tablet
};
3168 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3169 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3172 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3175 my $gpu_passthrough;
3178 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3179 my $d = parse_hostpci
($conf->{"hostpci$i"});
3182 my $pcie = $d->{pcie
};
3184 die "q35 machine model is not enabled" if !$q35;
3185 $pciaddr = print_pcie_addr
("hostpci$i");
3187 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3190 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3191 my $romfile = $d->{romfile
};
3194 if ($d->{'x-vga'}) {
3195 $xvga = ',x-vga=on';
3198 $gpu_passthrough = 1;
3200 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3204 my $pcidevices = $d->{pciid
};
3205 my $multifunction = 1 if @$pcidevices > 1;
3208 foreach my $pcidevice (@$pcidevices) {
3210 my $id = "hostpci$i";
3211 $id .= ".$j" if $multifunction;
3212 my $addr = $pciaddr;
3213 $addr .= ".$j" if $multifunction;
3214 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3217 $devicestr .= "$rombar$xvga";
3218 $devicestr .= ",multifunction=on" if $multifunction;
3219 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3222 push @$devices, '-device', $devicestr;
3228 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3229 push @$devices, @usbdevices if @usbdevices;
3231 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3232 if (my $path = $conf->{"serial$i"}) {
3233 if ($path eq 'socket') {
3234 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3235 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3236 push @$devices, '-device', "isa-serial,chardev=serial$i";
3238 die "no such serial device\n" if ! -c
$path;
3239 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3240 push @$devices, '-device', "isa-serial,chardev=serial$i";
3246 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3247 if (my $path = $conf->{"parallel$i"}) {
3248 die "no such parallel device\n" if ! -c
$path;
3249 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3250 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3251 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3257 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3258 $sockets = $conf->{sockets
} if $conf->{sockets
};
3260 my $cores = $conf->{cores
} || 1;
3262 my $maxcpus = $sockets * $cores;
3264 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3266 my $allowed_vcpus = $cpuinfo->{cpus
};
3268 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3269 if ($allowed_vcpus < $maxcpus);
3271 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3273 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3274 for (my $i = 2; $i <= $vcpus; $i++) {
3275 my $cpustr = print_cpu_device
($conf,$i);
3276 push @$cmd, '-device', $cpustr;
3281 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3283 push @$cmd, '-nodefaults';
3285 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3287 my $bootindex_hash = {};
3289 foreach my $o (split(//, $bootorder)) {
3290 $bootindex_hash->{$o} = $i*100;
3294 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3296 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3298 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3300 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3302 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3303 my $socket = vnc_socket
($vmid);
3304 push @$cmd, '-vnc', "unix:$socket,x509,password";
3306 push @$cmd, '-nographic';
3310 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3312 my $useLocaltime = $conf->{localtime};
3314 if ($winversion >= 5) { # windows
3315 $useLocaltime = 1 if !defined($conf->{localtime});
3317 # use time drift fix when acpi is enabled
3318 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3319 $tdf = 1 if !defined($conf->{tdf
});
3323 if ($winversion >= 6) {
3324 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3325 push @$cmd, '-no-hpet';
3328 push @$rtcFlags, 'driftfix=slew' if $tdf;
3331 push @$machineFlags, 'accel=tcg';
3334 if ($machine_type) {
3335 push @$machineFlags, "type=${machine_type}";
3338 if ($conf->{startdate
}) {
3339 push @$rtcFlags, "base=$conf->{startdate}";
3340 } elsif ($useLocaltime) {
3341 push @$rtcFlags, 'base=localtime';
3344 my $cpu = $kvm ?
"kvm64" : "qemu64";
3345 if (my $cputype = $conf->{cpu
}) {
3346 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3347 or die "Cannot parse cpu description: $cputype\n";
3348 $cpu = $cpuconf->{cputype
};
3349 $kvm_off = 1 if $cpuconf->{hidden
};
3351 if (defined(my $flags = $cpuconf->{flags
})) {
3352 push @$cpuFlags, split(";", $flags);
3356 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3358 push @$cpuFlags , '-x2apic'
3359 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3361 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3363 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3365 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3367 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3368 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3371 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3373 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3375 push @$cpuFlags, 'kvm=off' if $kvm_off;
3377 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3378 die "internal error"; # should not happen
3380 push @$cpuFlags, "vendor=${cpu_vendor}"
3381 if $cpu_vendor ne 'default';
3383 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3385 push @$cmd, '-cpu', $cpu;
3387 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3389 push @$cmd, '-S' if $conf->{freeze
};
3391 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3394 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3395 #push @$cmd, '-soundhw', 'es1370';
3396 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3398 if($conf->{agent
}) {
3399 my $qgasocket = qmp_socket
($vmid, 1);
3400 my $pciaddr = print_pci_addr
("qga0", $bridges);
3401 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3402 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3403 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3411 for(my $i = 1; $i < $qxlnum; $i++){
3412 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3413 push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3416 # assume other OS works like Linux
3417 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3418 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3422 my $pciaddr = print_pci_addr
("spice", $bridges);
3424 my $nodename = PVE
::INotify
::nodename
();
3425 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3426 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3427 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3428 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3429 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3431 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3433 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3434 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3435 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3438 # enable balloon by default, unless explicitly disabled
3439 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3440 $pciaddr = print_pci_addr
("balloon0", $bridges);
3441 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3444 if ($conf->{watchdog
}) {
3445 my $wdopts = parse_watchdog
($conf->{watchdog
});
3446 $pciaddr = print_pci_addr
("watchdog", $bridges);
3447 my $watchdog = $wdopts->{model
} || 'i6300esb';
3448 push @$devices, '-device', "$watchdog$pciaddr";
3449 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3453 my $scsicontroller = {};
3454 my $ahcicontroller = {};
3455 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3457 # Add iscsi initiator name if available
3458 if (my $initiator = get_initiator_name
()) {
3459 push @$devices, '-iscsi', "initiator-name=$initiator";
3462 foreach_drive
($conf, sub {
3463 my ($ds, $drive) = @_;
3465 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3466 push @$vollist, $drive->{file
};
3469 # ignore efidisk here, already added in bios/fw handling code above
3470 return if $drive->{interface
} eq 'efidisk';
3472 $use_virtio = 1 if $ds =~ m/^virtio/;
3474 if (drive_is_cdrom
($drive)) {
3475 if ($bootindex_hash->{d
}) {
3476 $drive->{bootindex
} = $bootindex_hash->{d
};
3477 $bootindex_hash->{d
} += 1;
3480 if ($bootindex_hash->{c
}) {
3481 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3482 $bootindex_hash->{c
} += 1;
3486 if($drive->{interface
} eq 'virtio'){
3487 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3490 if ($drive->{interface
} eq 'scsi') {
3492 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3494 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3495 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3498 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3499 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3500 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3501 } elsif ($drive->{iothread
}) {
3502 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3506 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3507 $queues = ",num_queues=$drive->{queues}";
3510 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3511 $scsicontroller->{$controller}=1;
3514 if ($drive->{interface
} eq 'sata') {
3515 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3516 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3517 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3518 $ahcicontroller->{$controller}=1;
3521 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3522 push @$devices, '-drive',$drive_cmd;
3523 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3526 for (my $i = 0; $i < $MAX_NETS; $i++) {
3527 next if !$conf->{"net$i"};
3528 my $d = parse_net
($conf->{"net$i"});
3531 $use_virtio = 1 if $d->{model
} eq 'virtio';
3533 if ($bootindex_hash->{n
}) {
3534 $d->{bootindex
} = $bootindex_hash->{n
};
3535 $bootindex_hash->{n
} += 1;
3538 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3539 push @$devices, '-netdev', $netdevfull;
3541 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3542 push @$devices, '-device', $netdevicefull;
3547 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3552 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3554 while (my ($k, $v) = each %$bridges) {
3555 $pciaddr = print_pci_addr
("pci.$k");
3556 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3561 if ($conf->{args
}) {
3562 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3566 push @$cmd, @$devices;
3567 push @$cmd, '-rtc', join(',', @$rtcFlags)
3568 if scalar(@$rtcFlags);
3569 push @$cmd, '-machine', join(',', @$machineFlags)
3570 if scalar(@$machineFlags);
3571 push @$cmd, '-global', join(',', @$globalFlags)
3572 if scalar(@$globalFlags);
3574 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3579 return "${var_run_tmpdir}/$vmid.vnc";
3585 my $res = vm_mon_cmd
($vmid, 'query-spice');
3587 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3591 my ($vmid, $qga) = @_;
3592 my $sockettype = $qga ?
'qga' : 'qmp';
3593 return "${var_run_tmpdir}/$vmid.$sockettype";
3598 return "${var_run_tmpdir}/$vmid.pid";
3601 sub vm_devices_list
{
3604 my $res = vm_mon_cmd
($vmid, 'query-pci');
3605 my $devices_to_check = [];
3607 foreach my $pcibus (@$res) {
3608 push @$devices_to_check, @{$pcibus->{devices
}},
3611 while (@$devices_to_check) {
3613 for my $d (@$devices_to_check) {
3614 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3615 next if !$d->{'pci_bridge'};
3617 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3618 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3620 $devices_to_check = $to_check;
3623 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3624 foreach my $block (@$resblock) {
3625 if($block->{device
} =~ m/^drive-(\S+)/){
3630 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3631 foreach my $mice (@$resmice) {
3632 if ($mice->{name
} eq 'QEMU HID Tablet') {
3633 $devices->{tablet
} = 1;
3638 # for usb devices there is no query-usb
3639 # but we can iterate over the entries in
3640 # qom-list path=/machine/peripheral
3641 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3642 foreach my $per (@$resperipheral) {
3643 if ($per->{name
} =~ m/^usb\d+$/) {
3644 $devices->{$per->{name
}} = 1;
3652 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3654 my $q35 = machine_type_is_q35
($conf);
3656 my $devices_list = vm_devices_list
($vmid);
3657 return 1 if defined($devices_list->{$deviceid});
3659 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3661 if ($deviceid eq 'tablet') {
3663 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3665 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3667 die "usb hotplug currently not reliable\n";
3668 # since we can't reliably hot unplug all added usb devices
3669 # and usb passthrough disables live migration
3670 # we disable usb hotplugging for now
3671 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3673 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3675 qemu_iothread_add
($vmid, $deviceid, $device);
3677 qemu_driveadd
($storecfg, $vmid, $device);
3678 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3680 qemu_deviceadd
($vmid, $devicefull);
3681 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3683 eval { qemu_drivedel
($vmid, $deviceid); };
3688 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3691 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3692 my $pciaddr = print_pci_addr
($deviceid);
3693 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3695 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3697 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3698 qemu_iothread_add
($vmid, $deviceid, $device);
3699 $devicefull .= ",iothread=iothread-$deviceid";
3702 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3703 $devicefull .= ",num_queues=$device->{queues}";
3706 qemu_deviceadd
($vmid, $devicefull);
3707 qemu_deviceaddverify
($vmid, $deviceid);
3709 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3711 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3712 qemu_driveadd
($storecfg, $vmid, $device);
3714 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3715 eval { qemu_deviceadd
($vmid, $devicefull); };
3717 eval { qemu_drivedel
($vmid, $deviceid); };
3722 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3724 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3726 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3727 my $use_old_bios_files = undef;
3728 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3730 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3731 qemu_deviceadd
($vmid, $netdevicefull);
3732 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3734 eval { qemu_netdevdel
($vmid, $deviceid); };
3739 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3742 my $pciaddr = print_pci_addr
($deviceid);
3743 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3745 qemu_deviceadd
($vmid, $devicefull);
3746 qemu_deviceaddverify
($vmid, $deviceid);
3749 die "can't hotplug device '$deviceid'\n";
3755 # fixme: this should raise exceptions on error!
3756 sub vm_deviceunplug
{
3757 my ($vmid, $conf, $deviceid) = @_;
3759 my $devices_list = vm_devices_list
($vmid);
3760 return 1 if !defined($devices_list->{$deviceid});
3762 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3764 if ($deviceid eq 'tablet') {
3766 qemu_devicedel
($vmid, $deviceid);
3768 } elsif ($deviceid =~ m/^usb\d+$/) {
3770 die "usb hotplug currently not reliable\n";
3771 # when unplugging usb devices this way,
3772 # there may be remaining usb controllers/hubs
3773 # so we disable it for now
3774 qemu_devicedel
($vmid, $deviceid);
3775 qemu_devicedelverify
($vmid, $deviceid);
3777 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3779 qemu_devicedel
($vmid, $deviceid);
3780 qemu_devicedelverify
($vmid, $deviceid);
3781 qemu_drivedel
($vmid, $deviceid);
3782 qemu_iothread_del
($conf, $vmid, $deviceid);
3784 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3786 qemu_devicedel
($vmid, $deviceid);
3787 qemu_devicedelverify
($vmid, $deviceid);
3788 qemu_iothread_del
($conf, $vmid, $deviceid);
3790 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3792 qemu_devicedel
($vmid, $deviceid);
3793 qemu_drivedel
($vmid, $deviceid);
3794 qemu_deletescsihw
($conf, $vmid, $deviceid);
3796 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3798 qemu_devicedel
($vmid, $deviceid);
3799 qemu_devicedelverify
($vmid, $deviceid);
3800 qemu_netdevdel
($vmid, $deviceid);
3803 die "can't unplug device '$deviceid'\n";
3809 sub qemu_deviceadd
{
3810 my ($vmid, $devicefull) = @_;
3812 $devicefull = "driver=".$devicefull;
3813 my %options = split(/[=,]/, $devicefull);
3815 vm_mon_cmd
($vmid, "device_add" , %options);
3818 sub qemu_devicedel
{
3819 my ($vmid, $deviceid) = @_;
3821 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3824 sub qemu_iothread_add
{
3825 my($vmid, $deviceid, $device) = @_;
3827 if ($device->{iothread
}) {
3828 my $iothreads = vm_iothreads_list
($vmid);
3829 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3833 sub qemu_iothread_del
{
3834 my($conf, $vmid, $deviceid) = @_;
3836 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3837 if ($device->{iothread
}) {
3838 my $iothreads = vm_iothreads_list
($vmid);
3839 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3843 sub qemu_objectadd
{
3844 my($vmid, $objectid, $qomtype) = @_;
3846 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3851 sub qemu_objectdel
{
3852 my($vmid, $objectid) = @_;
3854 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3860 my ($storecfg, $vmid, $device) = @_;
3862 my $drive = print_drive_full
($storecfg, $vmid, $device);
3863 $drive =~ s/\\/\\\\/g;
3864 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3866 # If the command succeeds qemu prints: "OK
"
3867 return 1 if $ret =~ m/OK/s;
3869 die "adding drive failed
: $ret\n";
3873 my($vmid, $deviceid) = @_;
3875 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3878 return 1 if $ret eq "";
3880 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3881 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3883 die "deleting drive
$deviceid failed
: $ret\n";
3886 sub qemu_deviceaddverify {
3887 my ($vmid, $deviceid) = @_;
3889 for (my $i = 0; $i <= 5; $i++) {
3890 my $devices_list = vm_devices_list($vmid);
3891 return 1 if defined($devices_list->{$deviceid});
3895 die "error on hotplug device
'$deviceid'\n";
3899 sub qemu_devicedelverify {
3900 my ($vmid, $deviceid) = @_;
3902 # need to verify that the device is correctly removed as device_del
3903 # is async and empty return is not reliable
3905 for (my $i = 0; $i <= 5; $i++) {
3906 my $devices_list = vm_devices_list($vmid);
3907 return 1 if !defined($devices_list->{$deviceid});
3911 die "error on hot-unplugging device
'$deviceid'\n";
3914 sub qemu_findorcreatescsihw {
3915 my ($storecfg, $conf, $vmid, $device) = @_;
3917 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3919 my $scsihwid="$controller_prefix$controller";
3920 my $devices_list = vm_devices_list($vmid);
3922 if(!defined($devices_list->{$scsihwid})) {
3923 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3929 sub qemu_deletescsihw {
3930 my ($conf, $vmid, $opt) = @_;
3932 my $device = parse_drive($opt, $conf->{$opt});
3934 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3935 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3939 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3941 my $devices_list = vm_devices_list($vmid);
3942 foreach my $opt (keys %{$devices_list}) {
3943 if (PVE::QemuServer::is_valid_drivename($opt)) {
3944 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3945 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3951 my $scsihwid="scsihw
$controller";
3953 vm_deviceunplug($vmid, $conf, $scsihwid);
3958 sub qemu_add_pci_bridge {
3959 my ($storecfg, $conf, $vmid, $device) = @_;
3965 print_pci_addr($device, $bridges);
3967 while (my ($k, $v) = each %$bridges) {
3970 return 1 if !defined($bridgeid) || $bridgeid < 1;
3972 my $bridge = "pci
.$bridgeid";
3973 my $devices_list = vm_devices_list($vmid);
3975 if (!defined($devices_list->{$bridge})) {
3976 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3982 sub qemu_set_link_status {
3983 my ($vmid, $device, $up) = @_;
3985 vm_mon_cmd($vmid, "set_link
", name => $device,
3986 up => $up ? JSON::true : JSON::false);
3989 sub qemu_netdevadd {
3990 my ($vmid, $conf, $device, $deviceid) = @_;
3992 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3993 my %options = split(/[=,]/, $netdev);
3995 vm_mon_cmd($vmid, "netdev_add
", %options);
3999 sub qemu_netdevdel {
4000 my ($vmid, $deviceid) = @_;
4002 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4005 sub qemu_usb_hotplug {
4006 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4010 # remove the old one first
4011 vm_deviceunplug($vmid, $conf, $deviceid);
4013 # check if xhci controller is necessary and available
4014 if ($device->{usb3}) {
4016 my $devicelist = vm_devices_list($vmid);
4018 if (!$devicelist->{xhci}) {
4019 my $pciaddr = print_pci_addr("xhci
");
4020 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4023 my $d = parse_usb_device($device->{host});
4024 $d->{usb3} = $device->{usb3};
4027 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4030 sub qemu_cpu_hotplug {
4031 my ($vmid, $conf, $vcpus) = @_;
4033 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4036 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4037 $sockets = $conf->{sockets} if $conf->{sockets};
4038 my $cores = $conf->{cores} || 1;
4039 my $maxcpus = $sockets * $cores;
4041 $vcpus = $maxcpus if !$vcpus;
4043 die "you can
't add more vcpus than maxcpus\n"
4044 if $vcpus > $maxcpus;
4046 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4048 if ($vcpus < $currentvcpus) {
4050 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4052 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4053 qemu_devicedel($vmid, "cpu$i");
4055 my $currentrunningvcpus = undef;
4057 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4058 last if scalar(@{$currentrunningvcpus}) == $i-1;
4059 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4063 #update conf after each succesfull cpu unplug
4064 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4065 PVE::QemuConfig->write_config($vmid, $conf);
4068 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4074 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4075 die "vcpus in running vm does not match its configuration\n"
4076 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4078 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4080 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4081 my $cpustr = print_cpu_device($conf, $i);
4082 qemu_deviceadd($vmid, $cpustr);
4085 my $currentrunningvcpus = undef;
4087 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4088 last if scalar(@{$currentrunningvcpus}) == $i;
4089 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4093 #update conf after each succesfull cpu hotplug
4094 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4095 PVE::QemuConfig->write_config($vmid, $conf);
4099 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4100 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4105 sub qemu_block_set_io_throttle {
4106 my ($vmid, $deviceid,
4107 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4108 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4109 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4110 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4112 return if !check_running($vmid) ;
4114 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4116 bps_rd => int($bps_rd),
4117 bps_wr => int($bps_wr),
4119 iops_rd => int($iops_rd),
4120 iops_wr => int($iops_wr),
4121 bps_max => int($bps_max),
4122 bps_rd_max => int($bps_rd_max),
4123 bps_wr_max => int($bps_wr_max),
4124 iops_max => int($iops_max),
4125 iops_rd_max => int($iops_rd_max),
4126 iops_wr_max => int($iops_wr_max),
4127 bps_max_length => int($bps_max_length),
4128 bps_rd_max_length => int($bps_rd_max_length),
4129 bps_wr_max_length => int($bps_wr_max_length),
4130 iops_max_length => int($iops_max_length),
4131 iops_rd_max_length => int($iops_rd_max_length),
4132 iops_wr_max_length => int($iops_wr_max_length),
4137 # old code, only used to shutdown old VM after update
4139 my ($fh, $timeout) = @_;
4141 my $sel = new IO::Select;
4148 while (scalar (@ready = $sel->can_read($timeout))) {
4150 if ($count = $fh->sysread($buf, 8192)) {
4151 if ($buf =~ /^(.*)\(qemu\) $/s) {
4158 if (!defined($count)) {
4165 die "monitor read timeout\n" if !scalar(@ready);
4170 sub qemu_block_resize {
4171 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4173 my $running = check_running($vmid);
4175 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4177 return if !$running;
4179 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4183 sub qemu_volume_snapshot {
4184 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4186 my $running = check_running($vmid);
4188 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4189 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4191 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4195 sub qemu_volume_snapshot_delete {
4196 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4198 my $running = check_running($vmid);
4203 my $conf = PVE::QemuConfig->load_config($vmid);
4204 foreach_drive($conf, sub {
4205 my ($ds, $drive) = @_;
4206 $running = 1 if $drive->{file} eq $volid;
4210 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4211 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4213 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4217 sub set_migration_caps {
4223 "auto-converge" => 1,
4225 "x-rdma-pin-all" => 0,
4230 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4232 for my $supported_capability (@$supported_capabilities) {
4234 capability => $supported_capability->{capability},
4235 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4239 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4242 my $fast_plug_option = {
4250 'vmstatestorage
' => 1,
4253 # hotplug changes in [PENDING]
4254 # $selection hash can be used to only apply specified options, for
4255 # example: { cores => 1 } (only apply changed 'cores
')
4256 # $errors ref is used to return error messages
4257 sub vmconfig_hotplug_pending {
4258 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4260 my $defaults = load_defaults();
4262 # commit values which do not have any impact on running VM first
4263 # Note: those option cannot raise errors, we we do not care about
4264 # $selection and always apply them.
4266 my $add_error = sub {
4267 my ($opt, $msg) = @_;
4268 $errors->{$opt} = "hotplug problem - $msg";
4272 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4273 if ($fast_plug_option->{$opt}) {
4274 $conf->{$opt} = $conf->{pending}->{$opt};
4275 delete $conf->{pending}->{$opt};
4281 PVE::QemuConfig->write_config($vmid, $conf);
4282 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4285 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4287 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4288 while (my ($opt, $force) = each %$pending_delete_hash) {
4289 next if $selection && !$selection->{$opt};
4291 if ($opt eq 'hotplug
') {
4292 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4293 } elsif ($opt eq 'tablet
') {
4294 die "skip\n" if !$hotplug_features->{usb};
4295 if ($defaults->{tablet}) {
4296 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4298 vm_deviceunplug($vmid, $conf, $opt);
4300 } elsif ($opt =~ m/^usb\d+/) {
4302 # since we cannot reliably hot unplug usb devices
4303 # we are disabling it
4304 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4305 vm_deviceunplug($vmid, $conf, $opt);
4306 } elsif ($opt eq 'vcpus
') {
4307 die "skip\n" if !$hotplug_features->{cpu};
4308 qemu_cpu_hotplug($vmid, $conf, undef);
4309 } elsif ($opt eq 'balloon
') {
4310 # enable balloon device is not hotpluggable
4311 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4312 # here we reset the ballooning value to memory
4313 my $balloon = $conf->{memory} || $defaults->{memory};
4314 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4315 } elsif ($fast_plug_option->{$opt}) {
4317 } elsif ($opt =~ m/^net(\d+)$/) {
4318 die "skip\n" if !$hotplug_features->{network};
4319 vm_deviceunplug($vmid, $conf, $opt);
4320 } elsif (is_valid_drivename($opt)) {
4321 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4322 vm_deviceunplug($vmid, $conf, $opt);
4323 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4324 } elsif ($opt =~ m/^memory$/) {
4325 die "skip\n" if !$hotplug_features->{memory};
4326 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4327 } elsif ($opt eq 'cpuunits
') {
4328 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4329 } elsif ($opt eq 'cpulimit
') {
4330 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4336 &$add_error($opt, $err) if $err ne "skip\n";
4338 # save new config if hotplug was successful
4339 delete $conf->{$opt};
4340 vmconfig_undelete_pending_option($conf, $opt);
4341 PVE::QemuConfig->write_config($vmid, $conf);
4342 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4346 my $apply_pending_cloudinit;
4347 $apply_pending_cloudinit = sub {
4348 my ($key, $value) = @_;
4349 $apply_pending_cloudinit = sub {}; # once is enough
4351 my @cloudinit_opts = keys %$confdesc_cloudinit;
4352 foreach my $opt (keys %{$conf->{pending}}) {
4353 next if !grep { $_ eq $opt } @cloudinit_opts;
4354 $conf->{$opt} = delete $conf->{pending}->{$opt};
4357 my $new_conf = { %$conf };
4358 $new_conf->{$key} = $value;
4359 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4362 foreach my $opt (keys %{$conf->{pending}}) {
4363 next if $selection && !$selection->{$opt};
4364 my $value = $conf->{pending}->{$opt};
4366 if ($opt eq 'hotplug
') {
4367 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4368 } elsif ($opt eq 'tablet
') {
4369 die "skip\n" if !$hotplug_features->{usb};
4371 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4372 } elsif ($value == 0) {
4373 vm_deviceunplug($vmid, $conf, $opt);
4375 } elsif ($opt =~ m/^usb\d+$/) {
4377 # since we cannot reliably hot unplug usb devices
4378 # we are disabling it
4379 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4380 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4381 die "skip\n" if !$d;
4382 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4383 } elsif ($opt eq 'vcpus
') {
4384 die "skip\n" if !$hotplug_features->{cpu};
4385 qemu_cpu_hotplug($vmid, $conf, $value);
4386 } elsif ($opt eq 'balloon
') {
4387 # enable/disable balloning device is not hotpluggable
4388 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4389 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4390 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4392 # allow manual ballooning if shares is set to zero
4393 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4394 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4395 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4397 } elsif ($opt =~ m/^net(\d+)$/) {
4398 # some changes can be done without hotplug
4399 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4400 $vmid, $opt, $value);
4401 } elsif (is_valid_drivename($opt)) {
4402 # some changes can be done without hotplug
4403 my $drive = parse_drive($opt, $value);
4404 if (drive_is_cloudinit($drive)) {
4405 &$apply_pending_cloudinit($opt, $value);
4407 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4408 $vmid, $opt, $value, 1);
4409 } elsif ($opt =~ m/^memory$/) { #dimms
4410 die "skip\n" if !$hotplug_features->{memory};
4411 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4412 } elsif ($opt eq 'cpuunits
') {
4413 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4414 } elsif ($opt eq 'cpulimit
') {
4415 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4416 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4418 die "skip\n"; # skip non-hot-pluggable options
4422 &$add_error($opt, $err) if $err ne "skip\n";
4424 # save new config if hotplug was successful
4425 $conf->{$opt} = $value;
4426 delete $conf->{pending}->{$opt};
4427 PVE::QemuConfig->write_config($vmid, $conf);
4428 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4433 sub try_deallocate_drive {
4434 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4436 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4437 my $volid = $drive->{file};
4438 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4439 my $sid = PVE::Storage::parse_volume_id($volid);
4440 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4442 # check if the disk is really unused
4443 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4444 if is_volume_in_use($storecfg, $conf, $key, $volid);
4445 PVE::Storage::vdisk_free($storecfg, $volid);
4448 # If vm is not owner of this disk remove from config
4456 sub vmconfig_delete_or_detach_drive {
4457 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4459 my $drive = parse_drive($opt, $conf->{$opt});
4461 my $rpcenv = PVE::RPCEnvironment::get();
4462 my $authuser = $rpcenv->get_user();
4465 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4466 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4468 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4472 sub vmconfig_apply_pending {
4473 my ($vmid, $conf, $storecfg) = @_;
4477 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4478 while (my ($opt, $force) = each %$pending_delete_hash) {
4479 die "internal error" if $opt =~ m/^unused/;
4480 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4481 if (!defined($conf->{$opt})) {
4482 vmconfig_undelete_pending_option($conf, $opt);
4483 PVE::QemuConfig->write_config($vmid, $conf);
4484 } elsif (is_valid_drivename($opt)) {
4485 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4486 vmconfig_undelete_pending_option($conf, $opt);
4487 delete $conf->{$opt};
4488 PVE::QemuConfig->write_config($vmid, $conf);
4490 vmconfig_undelete_pending_option($conf, $opt);
4491 delete $conf->{$opt};
4492 PVE::QemuConfig->write_config($vmid, $conf);
4496 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4498 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4499 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4501 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4502 # skip if nothing changed
4503 } elsif (is_valid_drivename($opt)) {
4504 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4505 if defined($conf->{$opt});
4506 $conf->{$opt} = $conf->{pending}->{$opt};
4508 $conf->{$opt} = $conf->{pending}->{$opt};
4511 delete $conf->{pending}->{$opt};
4512 PVE::QemuConfig->write_config($vmid, $conf);
4516 my $safe_num_ne = sub {
4519 return 0 if !defined($a) && !defined($b);
4520 return 1 if !defined($a);
4521 return 1 if !defined($b);
4526 my $safe_string_ne = sub {
4529 return 0 if !defined($a) && !defined($b);
4530 return 1 if !defined($a);
4531 return 1 if !defined($b);
4536 sub vmconfig_update_net {
4537 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4539 my $newnet = parse_net($value);
4541 if ($conf->{$opt}) {
4542 my $oldnet = parse_net($conf->{$opt});
4544 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4545 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4546 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4547 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4549 # for non online change, we try to hot-unplug
4550 die "skip\n" if !$hotplug;
4551 vm_deviceunplug($vmid, $conf, $opt);
4554 die "internal error" if $opt !~ m/net(\d+)/;
4555 my $iface = "tap${vmid}i$1";
4557 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4558 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4559 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4560 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4561 PVE::Network::tap_unplug($iface);
4562 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4563 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4564 # Rate can be applied on its own but any change above needs to
4565 # include the rate in tap_plug since OVS resets everything.
4566 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4569 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4570 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4578 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4584 sub vmconfig_update_disk {
4585 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4587 # fixme: do we need force?
4589 my $drive = parse_drive($opt, $value);
4591 if ($conf->{$opt}) {
4593 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4595 my $media = $drive->{media} || 'disk
';
4596 my $oldmedia = $old_drive->{media} || 'disk
';
4597 die "unable to change media type\n" if $media ne $oldmedia;
4599 if (!drive_is_cdrom($old_drive)) {
4601 if ($drive->{file} ne $old_drive->{file}) {
4603 die "skip\n" if !$hotplug;
4605 # unplug and register as unused
4606 vm_deviceunplug($vmid, $conf, $opt);
4607 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4610 # update existing disk
4612 # skip non hotpluggable value
4613 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4614 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4615 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4616 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4621 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4622 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4623 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4624 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4625 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4626 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4627 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4628 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4629 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4630 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4631 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4632 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4633 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4634 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4635 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4636 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4637 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4638 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4640 qemu_block_set_io_throttle($vmid,"drive-$opt",
4641 ($drive->{mbps} || 0)*1024*1024,
4642 ($drive->{mbps_rd} || 0)*1024*1024,
4643 ($drive->{mbps_wr} || 0)*1024*1024,
4644 $drive->{iops} || 0,
4645 $drive->{iops_rd} || 0,
4646 $drive->{iops_wr} || 0,
4647 ($drive->{mbps_max} || 0)*1024*1024,
4648 ($drive->{mbps_rd_max} || 0)*1024*1024,
4649 ($drive->{mbps_wr_max} || 0)*1024*1024,
4650 $drive->{iops_max} || 0,
4651 $drive->{iops_rd_max} || 0,
4652 $drive->{iops_wr_max} || 0,
4653 $drive->{bps_max_length} || 1,
4654 $drive->{bps_rd_max_length} || 1,
4655 $drive->{bps_wr_max_length} || 1,
4656 $drive->{iops_max_length} || 1,
4657 $drive->{iops_rd_max_length} || 1,
4658 $drive->{iops_wr_max_length} || 1);
4667 if ($drive->{file} eq 'none
') {
4668 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4669 if (drive_is_cloudinit($old_drive)) {
4670 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4673 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4674 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4675 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4683 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4685 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4686 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4690 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4691 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4693 PVE::QemuConfig->lock_config($vmid, sub {
4694 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4696 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4698 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4700 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4702 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4703 vmconfig_apply_pending($vmid, $conf, $storecfg);
4704 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4707 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4709 my $defaults = load_defaults();
4711 # set environment variable useful inside network script
4712 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4714 my $local_volumes = {};
4716 if ($targetstorage) {
4717 foreach_drive($conf, sub {
4718 my ($ds, $drive) = @_;
4720 return if drive_is_cdrom($drive);
4722 my $volid = $drive->{file};
4726 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4728 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4729 return if $scfg->{shared};
4730 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4735 foreach my $opt (sort keys %$local_volumes) {
4737 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4738 my $drive = parse_drive($opt, $conf->{$opt});
4740 #if remote storage is specified, use default format
4741 if ($targetstorage && $targetstorage ne "1") {
4742 $storeid = $targetstorage;
4743 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4744 $format = $defFormat;
4746 #else we use same format than original
4747 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4748 $format = qemu_img_format($scfg, $volid);
4751 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4752 my $newdrive = $drive;
4753 $newdrive->{format} = $format;
4754 $newdrive->{file} = $newvolid;
4755 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4756 $local_volumes->{$opt} = $drivestr;
4757 #pass drive to conf for command line
4758 $conf->{$opt} = $drivestr;
4762 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4764 my $migrate_port = 0;
4767 if ($statefile eq 'tcp
') {
4768 my $localip = "localhost";
4769 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4770 my $nodename = PVE::INotify::nodename();
4772 if (!defined($migration_type)) {
4773 if (defined($datacenterconf->{migration}->{type})) {
4774 $migration_type = $datacenterconf->{migration}->{type};
4776 $migration_type = 'secure
';
4780 if ($migration_type eq 'insecure
') {
4781 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4782 if ($migrate_network_addr) {
4783 $localip = $migrate_network_addr;
4785 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4788 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4791 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4792 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4793 $migrate_uri = "tcp:${localip}:${migrate_port}";
4794 push @$cmd, '-incoming
', $migrate_uri;
4797 } elsif ($statefile eq 'unix
') {
4798 # should be default for secure migrations as a ssh TCP forward
4799 # tunnel is not deterministic reliable ready and fails regurarly
4800 # to set up in time, so use UNIX socket forwards
4801 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4802 unlink $socket_addr;
4804 $migrate_uri = "unix:$socket_addr";
4806 push @$cmd, '-incoming
', $migrate_uri;
4810 push @$cmd, '-loadstate
', $statefile;
4817 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4818 my $d = parse_hostpci($conf->{"hostpci$i"});
4820 my $pcidevices = $d->{pciid};
4821 foreach my $pcidevice (@$pcidevices) {
4822 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4824 my $info = pci_device_info("0000:$pciid");
4825 die "IOMMU not present\n" if !check_iommu_support();
4826 die "no pci device info for device '$pciid'\n" if !$info;
4827 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4828 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4832 PVE::Storage::activate_volumes($storecfg, $vollist);
4834 if (!check_running($vmid, 1)) {
4836 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4837 outfunc => sub {}, errfunc => sub {});
4841 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4842 : $defaults->{cpuunits};
4844 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4845 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4848 Slice => 'qemu
.slice
',
4850 CPUShares => $cpuunits
4853 if (my $cpulimit = $conf->{cpulimit}) {
4854 $properties{CPUQuota} = int($cpulimit * 100);
4856 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4858 my $run_qemu = sub {
4859 PVE::Tools::run_fork sub {
4860 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4861 run_command($cmd, %run_params);
4865 if ($conf->{hugepages}) {
4868 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4869 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4871 PVE::QemuServer::Memory::hugepages_mount();
4872 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4874 eval { $run_qemu->() };
4876 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4880 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4882 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4885 eval { $run_qemu->() };
4889 # deactivate volumes if start fails
4890 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4891 die "start failed: $err";
4894 print "migration listens on $migrate_uri\n" if $migrate_uri;
4896 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4897 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4901 #start nbd server for storage migration
4902 if ($targetstorage) {
4903 my $nodename = PVE::INotify::nodename();
4904 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4905 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4906 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4907 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4909 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4911 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4913 foreach my $opt (sort keys %$local_volumes) {
4914 my $volid = $local_volumes->{$opt};
4915 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4916 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4917 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4921 if ($migratedfrom) {
4923 set_migration_caps($vmid);
4928 print "spice listens on port $spice_port\n";
4929 if ($spice_ticket) {
4930 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4931 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4936 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4937 if !$statefile && $conf->{balloon};
4939 foreach my $opt (keys %$conf) {
4940 next if $opt !~ m/^net\d+$/;
4941 my $nicconf = parse_net($conf->{$opt});
4942 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4946 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4947 path => "machine/peripheral/balloon0",
4948 property => "guest-stats-polling-interval",
4949 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4955 my ($vmid, $execute, %params) = @_;
4957 my $cmd = { execute => $execute, arguments => \%params };
4958 vm_qmp_command($vmid, $cmd);
4961 sub vm_mon_cmd_nocheck {
4962 my ($vmid, $execute, %params) = @_;
4964 my $cmd = { execute => $execute, arguments => \%params };
4965 vm_qmp_command($vmid, $cmd, 1);
4968 sub vm_qmp_command {
4969 my ($vmid, $cmd, $nocheck) = @_;
4974 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4975 $timeout = $cmd->{arguments}->{timeout};
4976 delete $cmd->{arguments}->{timeout};
4980 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4981 my $sname = qmp_socket($vmid);
4982 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4983 my $qmpclient = PVE::QMPClient->new();
4985 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4987 die "unable to open monitor socket\n";
4991 syslog("err", "VM $vmid qmp command failed - $err");
4998 sub vm_human_monitor_command {
4999 my ($vmid, $cmdline) = @_;
5004 execute => 'human-monitor-command
',
5005 arguments => { 'command-line
' => $cmdline},
5008 return vm_qmp_command($vmid, $cmd);
5011 sub vm_commandline {
5012 my ($storecfg, $vmid) = @_;
5014 my $conf = PVE::QemuConfig->load_config($vmid);
5016 my $defaults = load_defaults();
5018 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5020 return PVE::Tools::cmd2string($cmd);
5024 my ($vmid, $skiplock) = @_;
5026 PVE::QemuConfig->lock_config($vmid, sub {
5028 my $conf = PVE::QemuConfig->load_config($vmid);
5030 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5032 vm_mon_cmd($vmid, "system_reset");
5036 sub get_vm_volumes {
5040 foreach_volid($conf, sub {
5041 my ($volid, $attr) = @_;
5043 return if $volid =~ m|^/|;
5045 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5048 push @$vollist, $volid;
5054 sub vm_stop_cleanup {
5055 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5060 my $vollist = get_vm_volumes($conf);
5061 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5064 foreach my $ext (qw(mon qmp pid vnc qga)) {
5065 unlink "/var/run/qemu-server/${vmid}.$ext";
5068 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5070 warn $@ if $@; # avoid errors - just warn
5073 # Note: use $nockeck to skip tests if VM configuration file exists.
5074 # We need that when migration VMs to other nodes (files already moved)
5075 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5077 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5079 $force = 1 if !defined($force) && !$shutdown;
5082 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5083 kill 15, $pid if $pid;
5084 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5085 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5089 PVE
::QemuConfig-
>lock_config($vmid, sub {
5091 my $pid = check_running
($vmid, $nocheck);
5096 $conf = PVE
::QemuConfig-
>load_config($vmid);
5097 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5098 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5099 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5100 $timeout = $opts->{down
} if $opts->{down
};
5104 $timeout = 60 if !defined($timeout);
5108 if (defined($conf) && $conf->{agent
}) {
5109 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5111 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5114 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5121 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5126 if ($count >= $timeout) {
5128 warn "VM still running - terminating now with SIGTERM\n";
5131 die "VM quit/powerdown failed - got timeout\n";
5134 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5139 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5142 die "VM quit/powerdown failed\n";
5150 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5155 if ($count >= $timeout) {
5156 warn "VM still running - terminating now with SIGKILL\n";
5161 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5166 my ($vmid, $skiplock) = @_;
5168 PVE
::QemuConfig-
>lock_config($vmid, sub {
5170 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5172 PVE
::QemuConfig-
>check_lock($conf)
5173 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5175 vm_mon_cmd
($vmid, "stop");
5180 my ($vmid, $skiplock, $nocheck) = @_;
5182 PVE
::QemuConfig-
>lock_config($vmid, sub {
5184 my $res = vm_mon_cmd
($vmid, 'query-status');
5185 my $resume_cmd = 'cont';
5187 if ($res->{status
} && $res->{status
} eq 'suspended') {
5188 $resume_cmd = 'system_wakeup';
5193 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5195 PVE
::QemuConfig-
>check_lock($conf)
5196 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5198 vm_mon_cmd
($vmid, $resume_cmd);
5201 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5207 my ($vmid, $skiplock, $key) = @_;
5209 PVE
::QemuConfig-
>lock_config($vmid, sub {
5211 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5213 # there is no qmp command, so we use the human monitor command
5214 vm_human_monitor_command
($vmid, "sendkey $key");
5219 my ($storecfg, $vmid, $skiplock) = @_;
5221 PVE
::QemuConfig-
>lock_config($vmid, sub {
5223 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5225 if (!check_running
($vmid)) {
5226 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5228 die "VM $vmid is running - destroy failed\n";
5236 my ($filename, $buf) = @_;
5238 my $fh = IO
::File-
>new($filename, "w");
5239 return undef if !$fh;
5241 my $res = print $fh $buf;
5248 sub pci_device_info
{
5253 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5254 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5256 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5257 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5259 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5260 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5262 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5263 return undef if !defined($product) || $product !~ s/^0x//;
5268 product
=> $product,
5274 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5283 my $name = $dev->{name
};
5285 my $fn = "$pcisysfs/devices/$name/reset";
5287 return file_write
($fn, "1");
5290 sub pci_dev_bind_to_vfio
{
5293 my $name = $dev->{name
};
5295 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5297 if (!-d
$vfio_basedir) {
5298 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5300 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5302 my $testdir = "$vfio_basedir/$name";
5303 return 1 if -d
$testdir;
5305 my $data = "$dev->{vendor} $dev->{product}";
5306 return undef if !file_write
("$vfio_basedir/new_id", $data);
5308 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5309 if (!file_write
($fn, $name)) {
5310 return undef if -f
$fn;
5313 $fn = "$vfio_basedir/bind";
5314 if (! -d
$testdir) {
5315 return undef if !file_write
($fn, $name);
5321 sub pci_dev_group_bind_to_vfio
{
5324 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5326 if (!-d
$vfio_basedir) {
5327 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5329 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5331 # get IOMMU group devices
5332 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5333 my @devs = grep /^0000:/, readdir($D);
5336 foreach my $pciid (@devs) {
5337 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5339 # pci bridges, switches or root ports are not supported
5340 # they have a pci_bus subdirectory so skip them
5341 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5343 my $info = pci_device_info
($1);
5344 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5350 # vzdump restore implementaion
5352 sub tar_archive_read_firstfile
{
5353 my $archive = shift;
5355 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5357 # try to detect archive type first
5358 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5359 die "unable to open file '$archive'\n";
5360 my $firstfile = <$fh>;
5364 die "ERROR: archive contaions no data\n" if !$firstfile;
5370 sub tar_restore_cleanup
{
5371 my ($storecfg, $statfile) = @_;
5373 print STDERR
"starting cleanup\n";
5375 if (my $fd = IO
::File-
>new($statfile, "r")) {
5376 while (defined(my $line = <$fd>)) {
5377 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5380 if ($volid =~ m
|^/|) {
5381 unlink $volid || die 'unlink failed\n';
5383 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5385 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5387 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5389 print STDERR
"unable to parse line in statfile - $line";
5396 sub restore_archive
{
5397 my ($archive, $vmid, $user, $opts) = @_;
5399 my $format = $opts->{format
};
5402 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5403 $format = 'tar' if !$format;
5405 } elsif ($archive =~ m/\.tar$/) {
5406 $format = 'tar' if !$format;
5407 } elsif ($archive =~ m/.tar.lzo$/) {
5408 $format = 'tar' if !$format;
5410 } elsif ($archive =~ m/\.vma$/) {
5411 $format = 'vma' if !$format;
5412 } elsif ($archive =~ m/\.vma\.gz$/) {
5413 $format = 'vma' if !$format;
5415 } elsif ($archive =~ m/\.vma\.lzo$/) {
5416 $format = 'vma' if !$format;
5419 $format = 'vma' if !$format; # default
5422 # try to detect archive format
5423 if ($format eq 'tar') {
5424 return restore_tar_archive
($archive, $vmid, $user, $opts);
5426 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5430 sub restore_update_config_line
{
5431 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5433 return if $line =~ m/^\#qmdump\#/;
5434 return if $line =~ m/^\#vzdump\#/;
5435 return if $line =~ m/^lock:/;
5436 return if $line =~ m/^unused\d+:/;
5437 return if $line =~ m/^parent:/;
5438 return if $line =~ m/^template:/; # restored VM is never a template
5440 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5441 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5442 # try to convert old 1.X settings
5443 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5444 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5445 my ($model, $macaddr) = split(/\=/, $devconfig);
5446 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5449 bridge
=> "vmbr$ind",
5450 macaddr
=> $macaddr,
5452 my $netstr = print_net
($net);
5454 print $outfd "net$cookie->{netcount}: $netstr\n";
5455 $cookie->{netcount
}++;
5457 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5458 my ($id, $netstr) = ($1, $2);
5459 my $net = parse_net
($netstr);
5460 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5461 $netstr = print_net
($net);
5462 print $outfd "$id: $netstr\n";
5463 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5466 my $di = parse_drive
($virtdev, $value);
5467 if (defined($di->{backup
}) && !$di->{backup
}) {
5468 print $outfd "#$line";
5469 } elsif ($map->{$virtdev}) {
5470 delete $di->{format
}; # format can change on restore
5471 $di->{file
} = $map->{$virtdev};
5472 $value = print_drive
($vmid, $di);
5473 print $outfd "$virtdev: $value\n";
5477 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5478 my ($uuid, $uuid_str);
5479 UUID
::generate
($uuid);
5480 UUID
::unparse
($uuid, $uuid_str);
5481 my $smbios1 = parse_smbios1
($2);
5482 $smbios1->{uuid
} = $uuid_str;
5483 print $outfd $1.print_smbios1
($smbios1)."\n";
5490 my ($cfg, $vmid) = @_;
5492 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5494 my $volid_hash = {};
5495 foreach my $storeid (keys %$info) {
5496 foreach my $item (@{$info->{$storeid}}) {
5497 next if !($item->{volid
} && $item->{size
});
5498 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5499 $volid_hash->{$item->{volid
}} = $item;
5506 sub is_volume_in_use
{
5507 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5509 my $path = PVE
::Storage
::path
($storecfg, $volid);
5511 my $scan_config = sub {
5512 my ($cref, $snapname) = @_;
5514 foreach my $key (keys %$cref) {
5515 my $value = $cref->{$key};
5516 if (is_valid_drivename
($key)) {
5517 next if $skip_drive && $key eq $skip_drive;
5518 my $drive = parse_drive
($key, $value);
5519 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5520 return 1 if $volid eq $drive->{file
};
5521 if ($drive->{file
} =~ m!^/!) {
5522 return 1 if $drive->{file
} eq $path;
5524 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5526 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5528 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5536 return 1 if &$scan_config($conf);
5540 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5541 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5547 sub update_disksize
{
5548 my ($vmid, $conf, $volid_hash) = @_;
5551 my $prefix = "VM $vmid:";
5553 # used and unused disks
5554 my $referenced = {};
5556 # Note: it is allowed to define multiple storages with same path (alias), so
5557 # we need to check both 'volid' and real 'path' (two different volid can point
5558 # to the same path).
5560 my $referencedpath = {};
5563 foreach my $opt (keys %$conf) {
5564 if (is_valid_drivename
($opt)) {
5565 my $drive = parse_drive
($opt, $conf->{$opt});
5566 my $volid = $drive->{file
};
5569 $referenced->{$volid} = 1;
5570 if ($volid_hash->{$volid} &&
5571 (my $path = $volid_hash->{$volid}->{path
})) {
5572 $referencedpath->{$path} = 1;
5575 next if drive_is_cdrom
($drive);
5576 next if !$volid_hash->{$volid};
5578 $drive->{size
} = $volid_hash->{$volid}->{size
};
5579 my $new = print_drive
($vmid, $drive);
5580 if ($new ne $conf->{$opt}) {
5582 $conf->{$opt} = $new;
5583 print "$prefix update disk '$opt' information.\n";
5588 # remove 'unusedX' entry if volume is used
5589 foreach my $opt (keys %$conf) {
5590 next if $opt !~ m/^unused\d+$/;
5591 my $volid = $conf->{$opt};
5592 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5593 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5594 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5596 delete $conf->{$opt};
5599 $referenced->{$volid} = 1;
5600 $referencedpath->{$path} = 1 if $path;
5603 foreach my $volid (sort keys %$volid_hash) {
5604 next if $volid =~ m/vm-$vmid-state-/;
5605 next if $referenced->{$volid};
5606 my $path = $volid_hash->{$volid}->{path
};
5607 next if !$path; # just to be sure
5608 next if $referencedpath->{$path};
5610 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5611 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5612 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5619 my ($vmid, $nolock, $dryrun) = @_;
5621 my $cfg = PVE
::Storage
::config
();
5623 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5624 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5625 foreach my $stor (keys %{$cfg->{ids
}}) {
5626 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5629 print "rescan volumes...\n";
5630 my $volid_hash = scan_volids
($cfg, $vmid);
5632 my $updatefn = sub {
5635 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5637 PVE
::QemuConfig-
>check_lock($conf);
5640 foreach my $volid (keys %$volid_hash) {
5641 my $info = $volid_hash->{$volid};
5642 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5645 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5647 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5650 if (defined($vmid)) {
5654 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5657 my $vmlist = config_list
();
5658 foreach my $vmid (keys %$vmlist) {
5662 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5668 sub restore_vma_archive
{
5669 my ($archive, $vmid, $user, $opts, $comp) = @_;
5671 my $readfrom = $archive;
5673 my $cfg = PVE
::Storage
::config
();
5675 my $bwlimit = $opts->{bwlimit
};
5677 my $dbg_cmdstring = '';
5678 my $add_pipe = sub {
5680 push @$commands, $cmd;
5681 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5682 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5687 if ($archive eq '-') {
5690 # If we use a backup from a PVE defined storage we also consider that
5691 # storage's rate limit:
5692 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5693 if (defined($volid)) {
5694 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5695 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5697 print STDERR
"applying read rate limit: $readlimit\n";
5698 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5699 $add_pipe->($cstream);
5706 if ($comp eq 'gzip') {
5707 $cmd = ['zcat', $readfrom];
5708 } elsif ($comp eq 'lzop') {
5709 $cmd = ['lzop', '-d', '-c', $readfrom];
5711 die "unknown compression method '$comp'\n";
5716 my $tmpdir = "/var/tmp/vzdumptmp$$";
5719 # disable interrupts (always do cleanups)
5723 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5725 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5726 POSIX
::mkfifo
($mapfifo, 0600);
5729 my $openfifo = sub {
5730 open($fifofh, '>', $mapfifo) || die $!;
5733 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5740 my $rpcenv = PVE
::RPCEnvironment
::get
();
5742 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5743 my $tmpfn = "$conffile.$$.tmp";
5745 # Note: $oldconf is undef if VM does not exists
5746 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5747 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5751 my $print_devmap = sub {
5752 my $virtdev_hash = {};
5754 my $cfgfn = "$tmpdir/qemu-server.conf";
5756 # we can read the config - that is already extracted
5757 my $fh = IO
::File-
>new($cfgfn, "r") ||
5758 "unable to read qemu-server.conf - $!\n";
5760 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5762 my $pve_firewall_dir = '/etc/pve/firewall';
5763 mkdir $pve_firewall_dir; # make sure the dir exists
5764 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5767 while (defined(my $line = <$fh>)) {
5768 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5769 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5770 die "archive does not contain data for drive '$virtdev'\n"
5771 if !$devinfo->{$devname};
5772 if (defined($opts->{storage
})) {
5773 $storeid = $opts->{storage
} || 'local';
5774 } elsif (!$storeid) {
5777 $format = 'raw' if !$format;
5778 $devinfo->{$devname}->{devname
} = $devname;
5779 $devinfo->{$devname}->{virtdev
} = $virtdev;
5780 $devinfo->{$devname}->{format
} = $format;
5781 $devinfo->{$devname}->{storeid
} = $storeid;
5783 # check permission on storage
5784 my $pool = $opts->{pool
}; # todo: do we need that?
5785 if ($user ne 'root@pam') {
5786 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5789 $storage_limits{$storeid} = $bwlimit;
5791 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5795 foreach my $key (keys %storage_limits) {
5796 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
5798 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
5799 $storage_limits{$key} = $limit * 1024;
5802 foreach my $devname (keys %$devinfo) {
5803 die "found no device mapping information for device '$devname'\n"
5804 if !$devinfo->{$devname}->{virtdev
};
5807 # create empty/temp config
5809 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5810 foreach_drive
($oldconf, sub {
5811 my ($ds, $drive) = @_;
5813 return if drive_is_cdrom
($drive);
5815 my $volid = $drive->{file
};
5817 return if !$volid || $volid =~ m
|^/|;
5819 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5820 return if !$path || !$owner || ($owner != $vmid);
5822 # Note: only delete disk we want to restore
5823 # other volumes will become unused
5824 if ($virtdev_hash->{$ds}) {
5825 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5832 # delete vmstate files
5833 # since after the restore we have no snapshots anymore
5834 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5835 my $snap = $oldconf->{snapshots
}->{$snapname};
5836 if ($snap->{vmstate
}) {
5837 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5846 foreach my $virtdev (sort keys %$virtdev_hash) {
5847 my $d = $virtdev_hash->{$virtdev};
5848 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5849 my $storeid = $d->{storeid
};
5850 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
5853 if (my $limit = $storage_limits{$storeid}) {
5854 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
5857 # test if requested format is supported
5858 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
5859 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5860 $d->{format
} = $defFormat if !$supported;
5862 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
5863 $d->{format
}, undef, $alloc_size);
5864 print STDERR
"new volume ID is '$volid'\n";
5865 $d->{volid
} = $volid;
5866 my $path = PVE
::Storage
::path
($cfg, $volid);
5868 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5870 my $write_zeros = 1;
5871 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5875 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5877 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5878 $map->{$virtdev} = $volid;
5881 $fh->seek(0, 0) || die "seek failed - $!\n";
5883 my $outfd = new IO
::File
($tmpfn, "w") ||
5884 die "unable to write config for VM $vmid\n";
5886 my $cookie = { netcount
=> 0 };
5887 while (defined(my $line = <$fh>)) {
5888 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5901 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5902 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5904 $oldtimeout = alarm($timeout);
5911 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5912 my ($dev_id, $size, $devname) = ($1, $2, $3);
5913 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5914 } elsif ($line =~ m/^CTIME: /) {
5915 # we correctly received the vma config, so we can disable
5916 # the timeout now for disk allocation (set to 10 minutes, so
5917 # that we always timeout if something goes wrong)
5920 print $fifofh "done\n";
5921 my $tmp = $oldtimeout || 0;
5922 $oldtimeout = undef;
5928 print "restore vma archive: $dbg_cmdstring\n";
5929 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5933 alarm($oldtimeout) if $oldtimeout;
5936 foreach my $devname (keys %$devinfo) {
5937 my $volid = $devinfo->{$devname}->{volid
};
5938 push @$vollist, $volid if $volid;
5941 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5949 foreach my $devname (keys %$devinfo) {
5950 my $volid = $devinfo->{$devname}->{volid
};
5953 if ($volid =~ m
|^/|) {
5954 unlink $volid || die 'unlink failed\n';
5956 PVE
::Storage
::vdisk_free
($cfg, $volid);
5958 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5960 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5967 rename($tmpfn, $conffile) ||
5968 die "unable to commit configuration file '$conffile'\n";
5970 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5972 eval { rescan
($vmid, 1); };
5976 sub restore_tar_archive
{
5977 my ($archive, $vmid, $user, $opts) = @_;
5979 if ($archive ne '-') {
5980 my $firstfile = tar_archive_read_firstfile
($archive);
5981 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5982 if $firstfile ne 'qemu-server.conf';
5985 my $storecfg = PVE
::Storage
::config
();
5987 # destroy existing data - keep empty config
5988 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5989 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5991 my $tocmd = "/usr/lib/qemu-server/qmextract";
5993 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5994 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5995 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5996 $tocmd .= ' --info' if $opts->{info
};
5998 # tar option "xf" does not autodetect compression when read from STDIN,
5999 # so we pipe to zcat
6000 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6001 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6003 my $tmpdir = "/var/tmp/vzdumptmp$$";
6006 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6007 local $ENV{VZDUMP_VMID
} = $vmid;
6008 local $ENV{VZDUMP_USER
} = $user;
6010 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6011 my $tmpfn = "$conffile.$$.tmp";
6013 # disable interrupts (always do cleanups)
6017 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6025 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6027 if ($archive eq '-') {
6028 print "extracting archive from STDIN\n";
6029 run_command
($cmd, input
=> "<&STDIN");
6031 print "extracting archive '$archive'\n";
6035 return if $opts->{info
};
6039 my $statfile = "$tmpdir/qmrestore.stat";
6040 if (my $fd = IO
::File-
>new($statfile, "r")) {
6041 while (defined (my $line = <$fd>)) {
6042 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6043 $map->{$1} = $2 if $1;
6045 print STDERR
"unable to parse line in statfile - $line\n";
6051 my $confsrc = "$tmpdir/qemu-server.conf";
6053 my $srcfd = new IO
::File
($confsrc, "r") ||
6054 die "unable to open file '$confsrc'\n";
6056 my $outfd = new IO
::File
($tmpfn, "w") ||
6057 die "unable to write config for VM $vmid\n";
6059 my $cookie = { netcount
=> 0 };
6060 while (defined (my $line = <$srcfd>)) {
6061 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6073 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6080 rename $tmpfn, $conffile ||
6081 die "unable to commit configuration file '$conffile'\n";
6083 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6085 eval { rescan
($vmid, 1); };
6089 sub foreach_storage_used_by_vm
{
6090 my ($conf, $func) = @_;
6094 foreach_drive
($conf, sub {
6095 my ($ds, $drive) = @_;
6096 return if drive_is_cdrom
($drive);
6098 my $volid = $drive->{file
};
6100 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6101 $sidhash->{$sid} = $sid if $sid;
6104 foreach my $sid (sort keys %$sidhash) {
6109 sub do_snapshots_with_qemu
{
6110 my ($storecfg, $volid) = @_;
6112 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6114 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6115 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6119 if ($volid =~ m/\.(qcow2|qed)$/){
6126 sub qga_check_running
{
6127 my ($vmid, $nowarn) = @_;
6129 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6131 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6137 sub template_create
{
6138 my ($vmid, $conf, $disk) = @_;
6140 my $storecfg = PVE
::Storage
::config
();
6142 foreach_drive
($conf, sub {
6143 my ($ds, $drive) = @_;
6145 return if drive_is_cdrom
($drive);
6146 return if $disk && $ds ne $disk;
6148 my $volid = $drive->{file
};
6149 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6151 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6152 $drive->{file
} = $voliddst;
6153 $conf->{$ds} = print_drive
($vmid, $drive);
6154 PVE
::QemuConfig-
>write_config($vmid, $conf);
6158 sub qemu_img_convert
{
6159 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6161 my $storecfg = PVE
::Storage
::config
();
6162 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6163 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6165 if ($src_storeid && $dst_storeid) {
6167 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6169 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6170 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6172 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6173 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6175 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6176 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6179 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6180 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6181 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6182 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6183 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6184 if ($is_zero_initialized) {
6185 push @$cmd, "zeroinit:$dst_path";
6187 push @$cmd, $dst_path;
6192 if($line =~ m/\((\S+)\/100\
%\)/){
6194 my $transferred = int($size * $percent / 100);
6195 my $remaining = $size - $transferred;
6197 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6202 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6204 die "copy failed: $err" if $err;
6208 sub qemu_img_format
{
6209 my ($scfg, $volname) = @_;
6211 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6218 sub qemu_drive_mirror
{
6219 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6221 $jobs = {} if !$jobs;
6225 $jobs->{"drive-$drive"} = {};
6227 if ($dst_volid =~ /^nbd:/) {
6228 $qemu_target = $dst_volid;
6231 my $storecfg = PVE
::Storage
::config
();
6232 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6234 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6236 $format = qemu_img_format
($dst_scfg, $dst_volname);
6238 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6240 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6243 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6244 $opts->{format
} = $format if $format;
6246 print "drive mirror is starting for drive-$drive\n";
6248 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6251 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6252 die "mirroring error: $err";
6255 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6258 sub qemu_drive_mirror_monitor
{
6259 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6262 my $err_complete = 0;
6265 die "storage migration timed out\n" if $err_complete > 300;
6267 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6269 my $running_mirror_jobs = {};
6270 foreach my $stat (@$stats) {
6271 next if $stat->{type
} ne 'mirror';
6272 $running_mirror_jobs->{$stat->{device
}} = $stat;
6275 my $readycounter = 0;
6277 foreach my $job (keys %$jobs) {
6279 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6280 print "$job : finished\n";
6281 delete $jobs->{$job};
6285 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6287 my $busy = $running_mirror_jobs->{$job}->{busy
};
6288 my $ready = $running_mirror_jobs->{$job}->{ready
};
6289 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6290 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6291 my $remaining = $total - $transferred;
6292 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6294 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6297 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6300 last if scalar(keys %$jobs) == 0;
6302 if ($readycounter == scalar(keys %$jobs)) {
6303 print "all mirroring jobs are ready \n";
6304 last if $skipcomplete; #do the complete later
6306 if ($vmiddst && $vmiddst != $vmid) {
6307 my $agent_running = $qga && qga_check_running
($vmid);
6308 if ($agent_running) {
6309 print "freeze filesystem\n";
6310 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6312 print "suspend vm\n";
6313 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6316 # if we clone a disk for a new target vm, we don't switch the disk
6317 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6319 if ($agent_running) {
6320 print "unfreeze filesystem\n";
6321 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6323 print "resume vm\n";
6324 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6330 foreach my $job (keys %$jobs) {
6331 # try to switch the disk if source and destination are on the same guest
6332 print "$job: Completing block job...\n";
6334 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6335 if ($@ =~ m/cannot be completed/) {
6336 print "$job: Block job cannot be completed, try again.\n";
6339 print "$job: Completed successfully.\n";
6340 $jobs->{$job}->{complete
} = 1;
6351 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6352 die "mirroring error: $err";
6357 sub qemu_blockjobs_cancel
{
6358 my ($vmid, $jobs) = @_;
6360 foreach my $job (keys %$jobs) {
6361 print "$job: Cancelling block job\n";
6362 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6363 $jobs->{$job}->{cancel
} = 1;
6367 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6369 my $running_jobs = {};
6370 foreach my $stat (@$stats) {
6371 $running_jobs->{$stat->{device
}} = $stat;
6374 foreach my $job (keys %$jobs) {
6376 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6377 print "$job: Done.\n";
6378 delete $jobs->{$job};
6382 last if scalar(keys %$jobs) == 0;
6389 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6390 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6395 print "create linked clone of drive $drivename ($drive->{file})\n";
6396 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6397 push @$newvollist, $newvolid;
6400 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6401 $storeid = $storage if $storage;
6403 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6404 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6406 print "create full clone of drive $drivename ($drive->{file})\n";
6408 if (drive_is_cloudinit
($drive)) {
6409 $name = "vm-$newvmid-cloudinit";
6410 # cloudinit only supports raw and qcow2 atm:
6411 if ($dst_format eq 'qcow2') {
6413 } elsif ($dst_format ne 'raw') {
6414 die "clone: unhandled format for cloudinit image\n";
6417 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6418 push @$newvollist, $newvolid;
6420 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6422 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6423 if (!$running || $snapname) {
6424 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6427 my $kvmver = get_running_qemu_version
($vmid);
6428 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6429 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6430 if $drive->{iothread
};
6433 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6437 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6440 $disk->{format
} = undef;
6441 $disk->{file
} = $newvolid;
6442 $disk->{size
} = $size;
6447 # this only works if VM is running
6448 sub get_current_qemu_machine
{
6451 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6452 my $res = vm_qmp_command
($vmid, $cmd);
6454 my ($current, $default);
6455 foreach my $e (@$res) {
6456 $default = $e->{name
} if $e->{'is-default'};
6457 $current = $e->{name
} if $e->{'is-current'};
6460 # fallback to the default machine if current is not supported by qemu
6461 return $current || $default || 'pc';
6464 sub get_running_qemu_version
{
6466 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6467 my $res = vm_qmp_command
($vmid, $cmd);
6468 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6471 sub qemu_machine_feature_enabled
{
6472 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6477 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6479 $current_major = $3;
6480 $current_minor = $4;
6482 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6484 $current_major = $1;
6485 $current_minor = $2;
6488 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6493 sub qemu_machine_pxe
{
6494 my ($vmid, $conf, $machine) = @_;
6496 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6498 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6505 sub qemu_use_old_bios_files
{
6506 my ($machine_type) = @_;
6508 return if !$machine_type;
6510 my $use_old_bios_files = undef;
6512 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6514 $use_old_bios_files = 1;
6516 my $kvmver = kvm_user_version
();
6517 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6518 # load new efi bios files on migration. So this hack is required to allow
6519 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6520 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6521 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6524 return ($use_old_bios_files, $machine_type);
6527 sub create_efidisk
{
6528 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6530 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6532 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6533 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6534 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6536 my $path = PVE
::Storage
::path
($storecfg, $volid);
6538 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6540 die "Copying EFI vars image failed: $@" if $@;
6542 return ($volid, $vars_size);
6549 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6550 my (undef, $id, $function) = @_;
6551 my $res = { id
=> $id, function
=> $function};
6552 push @{$devices->{$id}}, $res;
6555 # Entries should be sorted by functions.
6556 foreach my $id (keys %$devices) {
6557 my $dev = $devices->{$id};
6558 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6564 sub vm_iothreads_list
{
6567 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6570 foreach my $iothread (@$res) {
6571 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6578 my ($conf, $drive) = @_;
6582 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6584 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6590 my $controller = int($drive->{index} / $maxdev);
6591 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6593 return ($maxdev, $controller, $controller_prefix);
6596 sub add_hyperv_enlightenments
{
6597 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6599 return if $winversion < 6;
6600 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6602 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6604 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6605 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6606 push @$cpuFlags , 'hv_vapic';
6607 push @$cpuFlags , 'hv_time';
6609 push @$cpuFlags , 'hv_spinlocks=0xffff';
6612 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6613 push @$cpuFlags , 'hv_reset';
6614 push @$cpuFlags , 'hv_vpindex';
6615 push @$cpuFlags , 'hv_runtime';
6618 if ($winversion >= 7) {
6619 push @$cpuFlags , 'hv_relaxed';
6623 sub windows_version
{
6626 return 0 if !$ostype;
6630 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6632 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6634 } elsif ($ostype =~ m/^win(\d+)$/) {
6641 sub resolve_dst_disk_format
{
6642 my ($storecfg, $storeid, $src_volname, $format) = @_;
6643 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6646 # if no target format is specified, use the source disk format as hint
6648 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6649 $format = qemu_img_format
($scfg, $src_volname);
6655 # test if requested format is supported - else use default
6656 my $supported = grep { $_ eq $format } @$validFormats;
6657 $format = $defFormat if !$supported;
6661 sub resolve_first_disk
{
6663 my @disks = PVE
::QemuServer
::valid_drive_names
();
6665 foreach my $ds (reverse @disks) {
6666 next if !$conf->{$ds};
6667 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6668 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6674 sub generate_smbios1_uuid
{
6675 my ($uuid, $uuid_str);
6676 UUID
::generate
($uuid);
6677 UUID
::unparse
($uuid, $uuid_str);
6678 return "uuid=$uuid_str";
6681 # bash completion helper
6683 sub complete_backup_archives
{
6684 my ($cmdname, $pname, $cvalue) = @_;
6686 my $cfg = PVE
::Storage
::config
();
6690 if ($cvalue =~ m/^([^:]+):/) {
6694 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6697 foreach my $id (keys %$data) {
6698 foreach my $item (@{$data->{$id}}) {
6699 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6700 push @$res, $item->{volid
} if defined($item->{volid
});
6707 my $complete_vmid_full = sub {
6710 my $idlist = vmstatus
();
6714 foreach my $id (keys %$idlist) {
6715 my $d = $idlist->{$id};
6716 if (defined($running)) {
6717 next if $d->{template
};
6718 next if $running && $d->{status
} ne 'running';
6719 next if !$running && $d->{status
} eq 'running';
6728 return &$complete_vmid_full();
6731 sub complete_vmid_stopped
{
6732 return &$complete_vmid_full(0);
6735 sub complete_vmid_running
{
6736 return &$complete_vmid_full(1);
6739 sub complete_storage
{
6741 my $cfg = PVE
::Storage
::config
();
6742 my $ids = $cfg->{ids
};
6745 foreach my $sid (keys %$ids) {
6746 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6747 next if !$ids->{$sid}->{content
}->{images
};
6757 vm_mon_cmd
($vmid, 'nbd-server-stop');