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
;
37 use Time
::HiRes
qw(gettimeofday);
38 use File
::Copy
qw(copy);
41 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
42 my $OVMF_CODE = "$EDK2_FW_BASE/OVMF_CODE.fd";
43 my $OVMF_VARS = "$EDK2_FW_BASE/OVMF_VARS.fd";
45 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
47 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
49 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
51 # Note about locking: we use flock on the config file protect
52 # against concurent actions.
53 # Aditionaly, we have a 'lock' setting in the config file. This
54 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
55 # allowed when such lock is set. But you can ignore this kind of
56 # lock with the --skiplock flag.
58 cfs_register_file
('/qemu-server/',
62 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
63 description
=> "Some command save/restore state from this location.",
69 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
70 description
=> "The name of the snapshot.",
71 type
=> 'string', format
=> 'pve-configid',
75 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
77 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
78 description
=> "The drive's backing file's data format.",
82 #no warnings 'redefine';
85 my ($controller, $vmid, $option, $value) = @_;
87 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
88 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
92 my $nodename = PVE
::INotify
::nodename
();
94 mkdir "/etc/pve/nodes/$nodename";
95 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
98 my $var_run_tmpdir = "/var/run/qemu-server";
99 mkdir $var_run_tmpdir;
101 my $lock_dir = "/var/lock/qemu-server";
104 my $pcisysfs = "/sys/bus/pci";
106 my $cpu_vendor_list = {
108 486 => 'GenuineIntel',
109 pentium
=> 'GenuineIntel',
110 pentium2
=> 'GenuineIntel',
111 pentium3
=> 'GenuineIntel',
112 coreduo
=> 'GenuineIntel',
113 core2duo
=> 'GenuineIntel',
114 Conroe
=> 'GenuineIntel',
115 Penryn
=> 'GenuineIntel',
116 Nehalem
=> 'GenuineIntel',
117 'Nehalem-IBRS' => 'GenuineIntel',
118 Westmere
=> 'GenuineIntel',
119 'Westmere-IBRS' => 'GenuineIntel',
120 SandyBridge
=> 'GenuineIntel',
121 'SandyBridge-IBRS' => 'GenuineIntel',
122 IvyBridge
=> 'GenuineIntel',
123 'IvyBridge-IBRS' => 'GenuineIntel',
124 Haswell
=> 'GenuineIntel',
125 'Haswell-IBRS' => 'GenuineIntel',
126 'Haswell-noTSX' => 'GenuineIntel',
127 'Haswell-noTSX-IBRS' => 'GenuineIntel',
128 Broadwell
=> 'GenuineIntel',
129 'Broadwell-IBRS' => 'GenuineIntel',
130 'Broadwell-noTSX' => 'GenuineIntel',
131 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
132 'Skylake-Client' => 'GenuineIntel',
133 'Skylake-Client-IBRS' => 'GenuineIntel',
134 'Skylake-Server' => 'GenuineIntel',
135 'Skylake-Server-IBRS' => 'GenuineIntel',
138 athlon
=> 'AuthenticAMD',
139 phenom
=> 'AuthenticAMD',
140 Opteron_G1
=> 'AuthenticAMD',
141 Opteron_G2
=> 'AuthenticAMD',
142 Opteron_G3
=> 'AuthenticAMD',
143 Opteron_G4
=> 'AuthenticAMD',
144 Opteron_G5
=> 'AuthenticAMD',
145 EPYC
=> 'AuthenticAMD',
146 'EPYC-IBPB' => 'AuthenticAMD',
148 # generic types, use vendor from host node
157 my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
161 description
=> "Emulated CPU type.",
163 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
168 description
=> "Do not identify as a KVM virtual machine.",
174 description
=> "List of additional CPU flags separated by ';'."
175 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
176 . " Currently supported flags: 'pcid', 'spec-ctrl'.",
177 format_description
=> '+FLAG[;-FLAG...]',
179 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
188 enum
=> [qw(i6300esb ib700)],
189 description
=> "Watchdog type to emulate.",
190 default => 'i6300esb',
195 enum
=> [qw(reset shutdown poweroff pause debug none)],
196 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
200 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
206 description
=> "Specifies whether a VM will be started during system bootup.",
212 description
=> "Automatic restart after crash (currently ignored).",
217 type
=> 'string', format
=> 'pve-hotplug-features',
218 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'.",
219 default => 'network,disk,usb',
224 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
230 description
=> "Lock/unlock the VM.",
231 enum
=> [qw(migrate backup snapshot rollback)],
236 description
=> "Limit of CPU usage.",
237 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.",
245 description
=> "CPU weight for a VM.",
246 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.",
254 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
261 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
267 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.",
275 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
276 "It should not be necessary to set it.",
277 enum
=> PVE
::Tools
::kvmkeymaplist
(),
282 type
=> 'string', format
=> 'dns-name',
283 description
=> "Set a name for the VM. Only used on the configuration web interface.",
288 description
=> "SCSI controller model",
289 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
295 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
300 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
301 description
=> "Specify guest operating system.",
302 verbose_description
=> <<EODESC,
303 Specify guest operating system. This is used to enable special
304 optimization/features for specific operating systems:
307 other;; unspecified OS
308 wxp;; Microsoft Windows XP
309 w2k;; Microsoft Windows 2000
310 w2k3;; Microsoft Windows 2003
311 w2k8;; Microsoft Windows 2008
312 wvista;; Microsoft Windows Vista
313 win7;; Microsoft Windows 7
314 win8;; Microsoft Windows 8/2012/2012r2
315 win10;; Microsoft Windows 10/2016
316 l24;; Linux 2.4 Kernel
317 l26;; Linux 2.6/3.X Kernel
318 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
324 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
325 pattern
=> '[acdn]{1,4}',
330 type
=> 'string', format
=> 'pve-qm-bootdisk',
331 description
=> "Enable booting from specified disk.",
332 pattern
=> '(ide|sata|scsi|virtio)\d+',
337 description
=> "The number of CPUs. Please use option -sockets instead.",
344 description
=> "The number of CPU sockets.",
351 description
=> "The number of cores per socket.",
358 description
=> "Enable/disable NUMA.",
364 description
=> "Enable/disable hugepages memory.",
365 enum
=> [qw(any 2 1024)],
370 description
=> "Number of hotplugged vcpus.",
377 description
=> "Enable/disable ACPI.",
383 description
=> "Enable/disable Qemu GuestAgent.",
389 description
=> "Enable/disable KVM hardware virtualization.",
395 description
=> "Enable/disable time drift fix.",
401 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
406 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
411 description
=> "Select the VGA type.",
412 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
413 " modes (>= 1280x1024x16) then you should use the options " .
414 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
415 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
416 "display sever. For win* OS you can select how many independent " .
417 "displays you want, Linux guests can add displays them self. " .
418 "You can also run without any graphic card, using a serial device" .
420 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
424 type
=> 'string', format
=> 'pve-qm-watchdog',
425 description
=> "Create a virtual hardware watchdog device.",
426 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
427 " (by a guest action), the watchdog must be periodically polled " .
428 "by an agent inside the guest or else the watchdog will reset " .
429 "the guest (or execute the respective action specified)",
434 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
435 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'.",
436 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
439 startup
=> get_standard_option
('pve-startup-order'),
443 description
=> "Enable/disable Template.",
449 description
=> "Arbitrary arguments passed to kvm.",
450 verbose_description
=> <<EODESCR,
451 Arbitrary arguments passed to kvm, for example:
453 args: -no-reboot -no-hpet
455 NOTE: this option is for experts only.
462 description
=> "Enable/disable the USB tablet device.",
463 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
464 "usually needed to allow absolute mouse positioning with VNC. " .
465 "Else the mouse runs out of sync with normal VNC clients. " .
466 "If you're running lots of console-only guests on one host, " .
467 "you may consider disabling this to save some context switches. " .
468 "This is turned off by default if you use spice (-vga=qxl).",
473 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
477 migrate_downtime
=> {
480 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
486 type
=> 'string', format
=> 'pve-qm-ide',
487 typetext
=> '<volume>',
488 description
=> "This is an alias for option -ide2",
492 description
=> "Emulated CPU type.",
496 parent
=> get_standard_option
('pve-snapshot-name', {
498 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
502 description
=> "Timestamp for snapshots.",
508 type
=> 'string', format
=> 'pve-volume-id',
509 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
511 vmstatestorage
=> get_standard_option
('pve-storage-id', {
512 description
=> "Default storage for VM state volumes/files.",
516 description
=> "Specific the Qemu machine type.",
518 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
523 description
=> "Specify SMBIOS type 1 fields.",
524 type
=> 'string', format
=> 'pve-qm-smbios1',
531 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
537 enum
=> [ qw(seabios ovmf) ],
538 description
=> "Select BIOS implementation.",
539 default => 'seabios',
543 my $confdesc_cloudinit = {
547 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.',
548 enum
=> ['configdrive2', 'nocloud'],
553 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
558 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.',
563 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.",
567 type
=> 'string', format
=> 'address-list',
568 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.",
573 format
=> 'urlencoded',
574 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
578 # what about other qemu settings ?
580 #machine => 'string',
593 ##soundhw => 'string',
595 while (my ($k, $v) = each %$confdesc) {
596 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
599 my $MAX_IDE_DISKS = 4;
600 my $MAX_SCSI_DISKS = 14;
601 my $MAX_VIRTIO_DISKS = 16;
602 my $MAX_SATA_DISKS = 6;
603 my $MAX_USB_DEVICES = 5;
605 my $MAX_UNUSED_DISKS = 8;
606 my $MAX_HOSTPCI_DEVICES = 4;
607 my $MAX_SERIAL_PORTS = 4;
608 my $MAX_PARALLEL_PORTS = 3;
614 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
615 description
=> "CPUs accessing this NUMA node.",
616 format_description
=> "id[-id];...",
620 description
=> "Amount of memory this NUMA node provides.",
625 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
626 description
=> "Host NUMA nodes to use.",
627 format_description
=> "id[-id];...",
632 enum
=> [qw(preferred bind interleave)],
633 description
=> "NUMA allocation policy.",
637 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
640 type
=> 'string', format
=> $numa_fmt,
641 description
=> "NUMA topology.",
643 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
645 for (my $i = 0; $i < $MAX_NUMA; $i++) {
646 $confdesc->{"numa$i"} = $numadesc;
649 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
650 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
651 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
652 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
654 my $net_fmt_bridge_descr = <<__EOD__;
655 Bridge to attach the network device to. The Proxmox VE standard bridge
658 If you do not specify a bridge, we create a kvm user (NATed) network
659 device, which provides DHCP and DNS services. The following addresses
666 The DHCP server assign addresses to the guest starting from 10.0.2.15.
672 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
673 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
674 format_description
=> "XX:XX:XX:XX:XX:XX",
679 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'.",
680 enum
=> $nic_model_list,
683 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
686 description
=> $net_fmt_bridge_descr,
687 format_description
=> 'bridge',
692 minimum
=> 0, maximum
=> 16,
693 description
=> 'Number of packet queues to be used on the device.',
699 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
704 minimum
=> 1, maximum
=> 4094,
705 description
=> 'VLAN tag to apply to packets on this interface.',
710 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
711 description
=> 'VLAN trunks to pass through this interface.',
712 format_description
=> 'vlanid[;vlanid...]',
717 description
=> 'Whether this interface should be protected by the firewall.',
722 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
729 type
=> 'string', format
=> $net_fmt,
730 description
=> "Specify network devices.",
733 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
738 format
=> 'pve-ipv4-config',
739 format_description
=> 'IPv4Format/CIDR',
740 description
=> 'IPv4 address in CIDR format.',
747 format_description
=> 'GatewayIPv4',
748 description
=> 'Default gateway for IPv4 traffic.',
754 format
=> 'pve-ipv6-config',
755 format_description
=> 'IPv6Format/CIDR',
756 description
=> 'IPv6 address in CIDR format.',
763 format_description
=> 'GatewayIPv6',
764 description
=> 'Default gateway for IPv6 traffic.',
769 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
772 type
=> 'string', format
=> 'pve-qm-ipconfig',
773 description
=> <<'EODESCR',
774 cloud-init: Specify IP addresses and gateways for the corresponding interface.
776 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
778 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
779 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
781 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
784 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
786 for (my $i = 0; $i < $MAX_NETS; $i++) {
787 $confdesc->{"net$i"} = $netdesc;
788 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
791 foreach my $key (keys %$confdesc_cloudinit) {
792 $confdesc->{$key} = $confdesc_cloudinit->{$key};
795 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
796 sub verify_volume_id_or_qm_path
{
797 my ($volid, $noerr) = @_;
799 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
803 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
804 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
806 return undef if $noerr;
814 my %drivedesc_base = (
815 volume
=> { alias
=> 'file' },
818 format
=> 'pve-volume-id-or-qm-path',
820 format_description
=> 'volume',
821 description
=> "The drive's backing volume.",
825 enum
=> [qw(cdrom disk)],
826 description
=> "The drive's media type.",
832 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
837 description
=> "Force the drive's physical geometry to have a specific head count.",
842 description
=> "Force the drive's physical geometry to have a specific sector count.",
847 enum
=> [qw(none lba auto)],
848 description
=> "Force disk geometry bios translation mode.",
853 description
=> "Controls qemu's snapshot mode feature."
854 . " If activated, changes made to the disk are temporary and will"
855 . " be discarded when the VM is shutdown.",
860 enum
=> [qw(none writethrough writeback unsafe directsync)],
861 description
=> "The drive's cache mode",
864 format
=> get_standard_option
('pve-qm-image-format'),
867 format
=> 'disk-size',
868 format_description
=> 'DiskSize',
869 description
=> "Disk size. This is purely informational and has no effect.",
874 description
=> "Whether the drive should be included when making backups.",
879 description
=> 'Whether the drive should considered for replication jobs.',
885 enum
=> [qw(ignore report stop)],
886 description
=> 'Read error action.',
891 enum
=> [qw(enospc ignore report stop)],
892 description
=> 'Write error action.',
897 enum
=> [qw(native threads)],
898 description
=> 'AIO type to use.',
903 enum
=> [qw(ignore on)],
904 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
909 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
914 format
=> 'urlencoded',
915 format_description
=> 'serial',
916 maxLength
=> 20*3, # *3 since it's %xx url enoded
917 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
922 description
=> 'Mark this locally-managed volume as available on all nodes',
923 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!",
929 my %iothread_fmt = ( iothread
=> {
931 description
=> "Whether to use iothreads for this drive",
938 format
=> 'urlencoded',
939 format_description
=> 'model',
940 maxLength
=> 40*3, # *3 since it's %xx url enoded
941 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
949 description
=> "Number of queues.",
955 my %scsiblock_fmt = (
958 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",
964 my $add_throttle_desc = sub {
965 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
968 format_description
=> $unit,
969 description
=> "Maximum $what in $longunit.",
972 $d->{minimum
} = $minimum if defined($minimum);
973 $drivedesc_base{$key} = $d;
975 # throughput: (leaky bucket)
976 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
977 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
978 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
979 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
980 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
981 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
982 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
983 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
984 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
986 # pools: (pool of IO before throttling starts taking effect)
987 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
988 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
989 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
990 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
991 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
992 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
995 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
996 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
997 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
998 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
999 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1000 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1003 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1004 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1005 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1006 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1012 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1016 type
=> 'string', format
=> $ide_fmt,
1017 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1019 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1029 type
=> 'string', format
=> $scsi_fmt,
1030 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1032 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1039 type
=> 'string', format
=> $sata_fmt,
1040 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1042 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1050 type
=> 'string', format
=> $virtio_fmt,
1051 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1053 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1055 my $alldrive_fmt = {
1064 volume
=> { alias
=> 'file' },
1067 format
=> 'pve-volume-id-or-qm-path',
1069 format_description
=> 'volume',
1070 description
=> "The drive's backing volume.",
1072 format
=> get_standard_option
('pve-qm-image-format'),
1075 format
=> 'disk-size',
1076 format_description
=> 'DiskSize',
1077 description
=> "Disk size. This is purely informational and has no effect.",
1082 my $efidisk_desc = {
1084 type
=> 'string', format
=> $efidisk_fmt,
1085 description
=> "Configure a Disk for storing EFI vars",
1088 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1093 type
=> 'string', format
=> 'pve-qm-usb-device',
1094 format_description
=> 'HOSTUSBDEVICE|spice',
1095 description
=> <<EODESCR,
1096 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1098 'bus-port(.port)*' (decimal numbers) or
1099 'vendor_id:product_id' (hexadeciaml numbers) or
1102 You can use the 'lsusb -t' command to list existing usb devices.
1104 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1106 The value 'spice' can be used to add a usb redirection devices for spice.
1112 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).",
1119 type
=> 'string', format
=> $usb_fmt,
1120 description
=> "Configure an USB device (n is 0 to 4).",
1122 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1124 # NOTE: the match-groups of this regex are used in parse_hostpci
1125 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1130 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1131 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1132 description
=> <<EODESCR,
1133 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1134 of PCI virtual functions of the host. HOSTPCIID syntax is:
1136 'bus:dev.func' (hexadecimal numbers)
1138 You can us the 'lspci' command to list existing PCI devices.
1143 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1149 pattern
=> '[^,;]+',
1150 format_description
=> 'string',
1151 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1156 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1162 description
=> "Enable vfio-vga device support.",
1167 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1171 type
=> 'string', format
=> 'pve-qm-hostpci',
1172 description
=> "Map host PCI devices into guest.",
1173 verbose_description
=> <<EODESCR,
1174 Map host PCI devices into guest.
1176 NOTE: This option allows direct access to host hardware. So it is no longer
1177 possible to migrate such machines - use with special care.
1179 CAUTION: Experimental! User reported problems with this option.
1182 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1187 pattern
=> '(/dev/.+|socket)',
1188 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1189 verbose_description
=> <<EODESCR,
1190 Create a serial device inside the VM (n is 0 to 3), and pass through a
1191 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1192 host side (use 'qm terminal' to open a terminal connection).
1194 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1196 CAUTION: Experimental! User reported problems with this option.
1203 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1204 description
=> "Map host parallel devices (n is 0 to 2).",
1205 verbose_description
=> <<EODESCR,
1206 Map host parallel devices (n is 0 to 2).
1208 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1210 CAUTION: Experimental! User reported problems with this option.
1214 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1215 $confdesc->{"parallel$i"} = $paralleldesc;
1218 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1219 $confdesc->{"serial$i"} = $serialdesc;
1222 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1223 $confdesc->{"hostpci$i"} = $hostpcidesc;
1226 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1227 $drivename_hash->{"ide$i"} = 1;
1228 $confdesc->{"ide$i"} = $idedesc;
1231 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1232 $drivename_hash->{"sata$i"} = 1;
1233 $confdesc->{"sata$i"} = $satadesc;
1236 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1237 $drivename_hash->{"scsi$i"} = 1;
1238 $confdesc->{"scsi$i"} = $scsidesc ;
1241 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1242 $drivename_hash->{"virtio$i"} = 1;
1243 $confdesc->{"virtio$i"} = $virtiodesc;
1246 $drivename_hash->{efidisk0
} = 1;
1247 $confdesc->{efidisk0
} = $efidisk_desc;
1249 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1250 $confdesc->{"usb$i"} = $usbdesc;
1255 type
=> 'string', format
=> 'pve-volume-id',
1256 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1259 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1260 $confdesc->{"unused$i"} = $unuseddesc;
1263 my $kvm_api_version = 0;
1267 return $kvm_api_version if $kvm_api_version;
1269 my $fh = IO
::File-
>new("</dev/kvm") ||
1272 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1273 $kvm_api_version = $v;
1278 return $kvm_api_version;
1281 my $kvm_user_version;
1283 sub kvm_user_version
{
1285 return $kvm_user_version if $kvm_user_version;
1287 $kvm_user_version = 'unknown';
1291 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1292 $kvm_user_version = $2;
1296 eval { run_command
("kvm -version", outfunc
=> $code); };
1299 return $kvm_user_version;
1303 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1305 sub valid_drive_names
{
1306 # order is important - used to autoselect boot disk
1307 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1308 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1309 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1310 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1314 sub is_valid_drivename
{
1317 return defined($drivename_hash->{$dev});
1322 return defined($confdesc->{$key});
1326 return $nic_model_list;
1329 sub os_list_description
{
1333 wxp
=> 'Windows XP',
1334 w2k
=> 'Windows 2000',
1335 w2k3
=>, 'Windows 2003',
1336 w2k8
=> 'Windows 2008',
1337 wvista
=> 'Windows Vista',
1338 win7
=> 'Windows 7',
1339 win8
=> 'Windows 8/2012',
1340 win10
=> 'Windows 10/2016',
1348 sub get_cdrom_path
{
1350 return $cdrom_path if $cdrom_path;
1352 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1353 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1354 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1358 my ($storecfg, $vmid, $cdrom) = @_;
1360 if ($cdrom eq 'cdrom') {
1361 return get_cdrom_path
();
1362 } elsif ($cdrom eq 'none') {
1364 } elsif ($cdrom =~ m
|^/|) {
1367 return PVE
::Storage
::path
($storecfg, $cdrom);
1371 # try to convert old style file names to volume IDs
1372 sub filename_to_volume_id
{
1373 my ($vmid, $file, $media) = @_;
1375 if (!($file eq 'none' || $file eq 'cdrom' ||
1376 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1378 return undef if $file =~ m
|/|;
1380 if ($media && $media eq 'cdrom') {
1381 $file = "local:iso/$file";
1383 $file = "local:$vmid/$file";
1390 sub verify_media_type
{
1391 my ($opt, $vtype, $media) = @_;
1396 if ($media eq 'disk') {
1398 } elsif ($media eq 'cdrom') {
1401 die "internal error";
1404 return if ($vtype eq $etype);
1406 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1409 sub cleanup_drive_path
{
1410 my ($opt, $storecfg, $drive) = @_;
1412 # try to convert filesystem paths to volume IDs
1414 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1415 ($drive->{file
} !~ m
|^/dev/.+|) &&
1416 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1417 ($drive->{file
} !~ m/^\d+$/)) {
1418 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1419 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1420 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1421 verify_media_type
($opt, $vtype, $drive->{media
});
1422 $drive->{file
} = $volid;
1425 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1428 sub parse_hotplug_features
{
1433 return $res if $data eq '0';
1435 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1437 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1438 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1441 die "invalid hotplug feature '$feature'\n";
1447 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1448 sub pve_verify_hotplug_features
{
1449 my ($value, $noerr) = @_;
1451 return $value if parse_hotplug_features
($value);
1453 return undef if $noerr;
1455 die "unable to parse hotplug option\n";
1458 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1459 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1460 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1461 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1462 # [,iothread=on][,serial=serial][,model=model]
1465 my ($key, $data) = @_;
1467 my ($interface, $index);
1469 if ($key =~ m/^([^\d]+)(\d+)$/) {
1476 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1477 : $confdesc->{$key}->{format
};
1479 warn "invalid drive key: $key\n";
1482 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1483 return undef if !$res;
1484 $res->{interface
} = $interface;
1485 $res->{index} = $index;
1488 foreach my $opt (qw(bps bps_rd bps_wr)) {
1489 if (my $bps = defined(delete $res->{$opt})) {
1490 if (defined($res->{"m$opt"})) {
1491 warn "both $opt and m$opt specified\n";
1495 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1499 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1500 for my $requirement (
1501 [mbps_max
=> 'mbps'],
1502 [mbps_rd_max
=> 'mbps_rd'],
1503 [mbps_wr_max
=> 'mbps_wr'],
1504 [miops_max
=> 'miops'],
1505 [miops_rd_max
=> 'miops_rd'],
1506 [miops_wr_max
=> 'miops_wr'],
1507 [bps_max_length
=> 'mbps_max'],
1508 [bps_rd_max_length
=> 'mbps_rd_max'],
1509 [bps_wr_max_length
=> 'mbps_wr_max'],
1510 [iops_max_length
=> 'iops_max'],
1511 [iops_rd_max_length
=> 'iops_rd_max'],
1512 [iops_wr_max_length
=> 'iops_wr_max']) {
1513 my ($option, $requires) = @$requirement;
1514 if ($res->{$option} && !$res->{$requires}) {
1515 warn "$option requires $requires\n";
1520 return undef if $error;
1522 return undef if $res->{mbps_rd
} && $res->{mbps
};
1523 return undef if $res->{mbps_wr
} && $res->{mbps
};
1524 return undef if $res->{iops_rd
} && $res->{iops
};
1525 return undef if $res->{iops_wr
} && $res->{iops
};
1527 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1528 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1529 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1530 return undef if $res->{interface
} eq 'virtio';
1533 if (my $size = $res->{size
}) {
1534 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1541 my ($vmid, $drive) = @_;
1542 my $data = { %$drive };
1543 delete $data->{$_} for qw(index interface);
1544 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1548 my($fh, $noerr) = @_;
1551 my $SG_GET_VERSION_NUM = 0x2282;
1553 my $versionbuf = "\x00" x
8;
1554 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1556 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1559 my $version = unpack("I", $versionbuf);
1560 if ($version < 30000) {
1561 die "scsi generic interface too old\n" if !$noerr;
1565 my $buf = "\x00" x
36;
1566 my $sensebuf = "\x00" x
8;
1567 my $cmd = pack("C x3 C x1", 0x12, 36);
1569 # see /usr/include/scsi/sg.h
1570 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";
1572 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1573 length($sensebuf), 0, length($buf), $buf,
1574 $cmd, $sensebuf, 6000);
1576 $ret = ioctl($fh, $SG_IO, $packet);
1578 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1582 my @res = unpack($sg_io_hdr_t, $packet);
1583 if ($res[17] || $res[18]) {
1584 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1589 (my $byte0, my $byte1, $res->{vendor
},
1590 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1592 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1593 $res->{type
} = $byte0 & 31;
1601 my $fh = IO
::File-
>new("+<$path") || return undef;
1602 my $res = scsi_inquiry
($fh, 1);
1608 sub machine_type_is_q35
{
1611 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1614 sub print_tabletdevice_full
{
1617 my $q35 = machine_type_is_q35
($conf);
1619 # we use uhci for old VMs because tablet driver was buggy in older qemu
1620 my $usbbus = $q35 ?
"ehci" : "uhci";
1622 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1625 sub print_drivedevice_full
{
1626 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1631 if ($drive->{interface
} eq 'virtio') {
1632 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1633 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1634 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1635 } elsif ($drive->{interface
} eq 'scsi') {
1637 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1638 my $unit = $drive->{index} % $maxdev;
1639 my $devicetype = 'hd';
1641 if (drive_is_cdrom
($drive)) {
1644 if ($drive->{file
} =~ m
|^/|) {
1645 $path = $drive->{file
};
1646 if (my $info = path_is_scsi
($path)) {
1647 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1648 $devicetype = 'block';
1649 } elsif ($info->{type
} == 1) { # tape
1650 $devicetype = 'generic';
1654 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1657 if($path =~ m/^iscsi\:\/\
//){
1658 $devicetype = 'generic';
1662 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1663 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1665 $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}";
1668 } elsif ($drive->{interface
} eq 'ide'){
1670 my $controller = int($drive->{index} / $maxdev);
1671 my $unit = $drive->{index} % $maxdev;
1672 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1674 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1675 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1676 $model = URI
::Escape
::uri_unescape
($model);
1677 $device .= ",model=$model";
1679 } elsif ($drive->{interface
} eq 'sata'){
1680 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1681 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1682 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1683 } elsif ($drive->{interface
} eq 'usb') {
1685 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1687 die "unsupported interface type";
1690 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1692 if (my $serial = $drive->{serial
}) {
1693 $serial = URI
::Escape
::uri_unescape
($serial);
1694 $device .= ",serial=$serial";
1701 sub get_initiator_name
{
1704 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1705 while (defined(my $line = <$fh>)) {
1706 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1715 sub print_drive_full
{
1716 my ($storecfg, $vmid, $drive) = @_;
1719 my $volid = $drive->{file
};
1722 if (drive_is_cdrom
($drive)) {
1723 $path = get_iso_path
($storecfg, $vmid, $volid);
1725 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1727 $path = PVE
::Storage
::path
($storecfg, $volid);
1728 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1729 $format = qemu_img_format
($scfg, $volname);
1737 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1738 foreach my $o (@qemu_drive_options) {
1739 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1742 # snapshot only accepts on|off
1743 if (defined($drive->{snapshot
})) {
1744 my $v = $drive->{snapshot
} ?
'on' : 'off';
1745 $opts .= ",snapshot=$v";
1748 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1749 my ($dir, $qmpname) = @$type;
1750 if (my $v = $drive->{"mbps$dir"}) {
1751 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1753 if (my $v = $drive->{"mbps${dir}_max"}) {
1754 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1756 if (my $v = $drive->{"bps${dir}_max_length"}) {
1757 $opts .= ",throttling.bps$qmpname-max-length=$v";
1759 if (my $v = $drive->{"iops${dir}"}) {
1760 $opts .= ",throttling.iops$qmpname=$v";
1762 if (my $v = $drive->{"iops${dir}_max"}) {
1763 $opts .= ",throttling.iops$qmpname-max=$v";
1765 if (my $v = $drive->{"iops${dir}_max_length"}) {
1766 $opts .= ",throttling.iops$qmpname-max-length=$v";
1770 $opts .= ",format=$format" if $format && !$drive->{format
};
1772 my $cache_direct = 0;
1774 if (my $cache = $drive->{cache
}) {
1775 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1776 } elsif (!drive_is_cdrom
($drive)) {
1777 $opts .= ",cache=none";
1781 # aio native works only with O_DIRECT
1782 if (!$drive->{aio
}) {
1784 $opts .= ",aio=native";
1786 $opts .= ",aio=threads";
1790 if (!drive_is_cdrom
($drive)) {
1792 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1793 $detectzeroes = 'off';
1794 } elsif ($drive->{discard
}) {
1795 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1797 # This used to be our default with discard not being specified:
1798 $detectzeroes = 'on';
1800 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1803 my $pathinfo = $path ?
"file=$path," : '';
1805 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1808 sub print_netdevice_full
{
1809 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1811 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1813 my $device = $net->{model
};
1814 if ($net->{model
} eq 'virtio') {
1815 $device = 'virtio-net-pci';
1818 my $pciaddr = print_pci_addr
("$netid", $bridges);
1819 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1820 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1821 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1822 my $vectors = $net->{queues
} * 2 + 2;
1823 $tmpstr .= ",vectors=$vectors,mq=on";
1825 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1827 if ($use_old_bios_files) {
1829 if ($device eq 'virtio-net-pci') {
1830 $romfile = 'pxe-virtio.rom';
1831 } elsif ($device eq 'e1000') {
1832 $romfile = 'pxe-e1000.rom';
1833 } elsif ($device eq 'ne2k') {
1834 $romfile = 'pxe-ne2k_pci.rom';
1835 } elsif ($device eq 'pcnet') {
1836 $romfile = 'pxe-pcnet.rom';
1837 } elsif ($device eq 'rtl8139') {
1838 $romfile = 'pxe-rtl8139.rom';
1840 $tmpstr .= ",romfile=$romfile" if $romfile;
1846 sub print_netdev_full
{
1847 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1850 if ($netid =~ m/^net(\d+)$/) {
1854 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1856 my $ifname = "tap${vmid}i$i";
1858 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1859 die "interface name '$ifname' is too long (max 15 character)\n"
1860 if length($ifname) >= 16;
1862 my $vhostparam = '';
1863 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1865 my $vmname = $conf->{name
} || "vm$vmid";
1868 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1870 if ($net->{bridge
}) {
1871 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1873 $netdev = "type=user,id=$netid,hostname=$vmname";
1876 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1882 sub print_cpu_device
{
1883 my ($conf, $id) = @_;
1885 my $kvm = $conf->{kvm
} // 1;
1886 my $cpu = $kvm ?
"kvm64" : "qemu64";
1887 if (my $cputype = $conf->{cpu
}) {
1888 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1889 or die "Cannot parse cpu description: $cputype\n";
1890 $cpu = $cpuconf->{cputype
};
1893 my $cores = $conf->{cores
} || 1;
1895 my $current_core = ($id - 1) % $cores;
1896 my $current_socket = int(($id - 1 - $current_core)/$cores);
1898 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1901 sub drive_is_cloudinit
{
1903 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1906 sub drive_is_cdrom
{
1907 my ($drive, $exclude_cloudinit) = @_;
1909 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1911 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1915 sub parse_number_sets
{
1918 foreach my $part (split(/;/, $set)) {
1919 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1920 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1921 push @$res, [ $1, $2 ];
1923 die "invalid range: $part\n";
1932 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1933 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1934 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1941 return undef if !$value;
1943 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1945 my @idlist = split(/;/, $res->{host
});
1946 delete $res->{host
};
1947 foreach my $id (@idlist) {
1948 if ($id =~ /^$PCIRE$/) {
1950 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1952 my $pcidevices = lspci
($1);
1953 $res->{pciid
} = $pcidevices->{$1};
1956 # should have been caught by parse_property_string already
1957 die "failed to parse PCI id: $id\n";
1963 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1967 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1972 if (!defined($res->{macaddr
})) {
1973 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1974 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1979 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1980 sub parse_ipconfig
{
1983 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1989 if ($res->{gw
} && !$res->{ip
}) {
1990 warn 'gateway specified without specifying an IP address';
1993 if ($res->{gw6
} && !$res->{ip6
}) {
1994 warn 'IPv6 gateway specified without specifying an IPv6 address';
1997 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1998 warn 'gateway specified together with DHCP';
2001 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2003 warn "IPv6 gateway specified together with $res->{ip6} address";
2007 if (!$res->{ip
} && !$res->{ip6
}) {
2008 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2017 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2020 sub add_random_macs
{
2021 my ($settings) = @_;
2023 foreach my $opt (keys %$settings) {
2024 next if $opt !~ m/^net(\d+)$/;
2025 my $net = parse_net
($settings->{$opt});
2027 $settings->{$opt} = print_net
($net);
2031 sub vm_is_volid_owner
{
2032 my ($storecfg, $vmid, $volid) = @_;
2034 if ($volid !~ m
|^/|) {
2036 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2037 if ($owner && ($owner == $vmid)) {
2045 sub split_flagged_list
{
2046 my $text = shift || '';
2047 $text =~ s/[,;]/ /g;
2049 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2052 sub join_flagged_list
{
2053 my ($how, $lst) = @_;
2054 join $how, map { $lst->{$_} . $_ } keys %$lst;
2057 sub vmconfig_delete_pending_option
{
2058 my ($conf, $key, $force) = @_;
2060 delete $conf->{pending
}->{$key};
2061 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2062 $pending_delete_hash->{$key} = $force ?
'!' : '';
2063 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2066 sub vmconfig_undelete_pending_option
{
2067 my ($conf, $key) = @_;
2069 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2070 delete $pending_delete_hash->{$key};
2072 if (%$pending_delete_hash) {
2073 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2075 delete $conf->{pending
}->{delete};
2079 sub vmconfig_register_unused_drive
{
2080 my ($storecfg, $vmid, $conf, $drive) = @_;
2082 if (drive_is_cloudinit
($drive)) {
2083 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2085 } elsif (!drive_is_cdrom
($drive)) {
2086 my $volid = $drive->{file
};
2087 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2088 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2093 sub vmconfig_cleanup_pending
{
2096 # remove pending changes when nothing changed
2098 foreach my $opt (keys %{$conf->{pending
}}) {
2099 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2101 delete $conf->{pending
}->{$opt};
2105 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2106 my $pending_delete_hash = {};
2107 while (my ($opt, $force) = each %$current_delete_hash) {
2108 if (defined($conf->{$opt})) {
2109 $pending_delete_hash->{$opt} = $force;
2115 if (%$pending_delete_hash) {
2116 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2118 delete $conf->{pending
}->{delete};
2124 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2128 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2129 format_description
=> 'UUID',
2130 description
=> "Set SMBIOS1 UUID.",
2136 format_description
=> 'string',
2137 description
=> "Set SMBIOS1 version.",
2143 format_description
=> 'string',
2144 description
=> "Set SMBIOS1 serial number.",
2150 format_description
=> 'string',
2151 description
=> "Set SMBIOS1 manufacturer.",
2157 format_description
=> 'string',
2158 description
=> "Set SMBIOS1 product ID.",
2164 format_description
=> 'string',
2165 description
=> "Set SMBIOS1 SKU string.",
2171 format_description
=> 'string',
2172 description
=> "Set SMBIOS1 family string.",
2180 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2187 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2190 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2192 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2193 sub verify_bootdisk
{
2194 my ($value, $noerr) = @_;
2196 return $value if is_valid_drivename
($value);
2198 return undef if $noerr;
2200 die "invalid boot disk '$value'\n";
2203 sub parse_watchdog
{
2206 return undef if !$value;
2208 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2213 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2214 sub verify_usb_device
{
2215 my ($value, $noerr) = @_;
2217 return $value if parse_usb_device
($value);
2219 return undef if $noerr;
2221 die "unable to parse usb device\n";
2224 # add JSON properties for create and set function
2225 sub json_config_properties
{
2228 foreach my $opt (keys %$confdesc) {
2229 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2230 $prop->{$opt} = $confdesc->{$opt};
2236 # return copy of $confdesc_cloudinit to generate documentation
2237 sub cloudinit_config_properties
{
2239 return dclone
($confdesc_cloudinit);
2243 my ($key, $value) = @_;
2245 die "unknown setting '$key'\n" if !$confdesc->{$key};
2247 my $type = $confdesc->{$key}->{type
};
2249 if (!defined($value)) {
2250 die "got undefined value\n";
2253 if ($value =~ m/[\n\r]/) {
2254 die "property contains a line feed\n";
2257 if ($type eq 'boolean') {
2258 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2259 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2260 die "type check ('boolean') failed - got '$value'\n";
2261 } elsif ($type eq 'integer') {
2262 return int($1) if $value =~ m/^(\d+)$/;
2263 die "type check ('integer') failed - got '$value'\n";
2264 } elsif ($type eq 'number') {
2265 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2266 die "type check ('number') failed - got '$value'\n";
2267 } elsif ($type eq 'string') {
2268 if (my $fmt = $confdesc->{$key}->{format
}) {
2269 PVE
::JSONSchema
::check_format
($fmt, $value);
2272 $value =~ s/^\"(.*)\"$/$1/;
2275 die "internal error"
2279 sub check_iommu_support
{
2280 #fixme : need to check IOMMU support
2281 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2291 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2292 utime undef, undef, $conf;
2296 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2298 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2300 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2302 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2304 if ($conf->{template
}) {
2305 # check if any base image is still used by a linked clone
2306 foreach_drive
($conf, sub {
2307 my ($ds, $drive) = @_;
2309 return if drive_is_cdrom
($drive);
2311 my $volid = $drive->{file
};
2313 return if !$volid || $volid =~ m
|^/|;
2315 die "base volume '$volid' is still in use by linked cloned\n"
2316 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2321 # only remove disks owned by this VM
2322 foreach_drive
($conf, sub {
2323 my ($ds, $drive) = @_;
2325 return if drive_is_cdrom
($drive, 1);
2327 my $volid = $drive->{file
};
2329 return if !$volid || $volid =~ m
|^/|;
2331 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2332 return if !$path || !$owner || ($owner != $vmid);
2335 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2337 warn "Could not remove disk '$volid', check manually: $@" if $@;
2341 if ($keep_empty_config) {
2342 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2347 # also remove unused disk
2349 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2352 PVE
::Storage
::foreach_volid
($dl, sub {
2353 my ($volid, $sid, $volname, $d) = @_;
2354 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2363 sub parse_vm_config
{
2364 my ($filename, $raw) = @_;
2366 return undef if !defined($raw);
2369 digest
=> Digest
::SHA
::sha1_hex
($raw),
2374 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2375 || die "got strange filename '$filename'";
2383 my @lines = split(/\n/, $raw);
2384 foreach my $line (@lines) {
2385 next if $line =~ m/^\s*$/;
2387 if ($line =~ m/^\[PENDING\]\s*$/i) {
2388 $section = 'pending';
2389 if (defined($descr)) {
2391 $conf->{description
} = $descr;
2394 $conf = $res->{$section} = {};
2397 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2399 if (defined($descr)) {
2401 $conf->{description
} = $descr;
2404 $conf = $res->{snapshots
}->{$section} = {};
2408 if ($line =~ m/^\#(.*)\s*$/) {
2409 $descr = '' if !defined($descr);
2410 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2414 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2415 $descr = '' if !defined($descr);
2416 $descr .= PVE
::Tools
::decode_text
($2);
2417 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2418 $conf->{snapstate
} = $1;
2419 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2422 $conf->{$key} = $value;
2423 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2425 if ($section eq 'pending') {
2426 $conf->{delete} = $value; # we parse this later
2428 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2430 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2433 eval { $value = check_type
($key, $value); };
2435 warn "vm $vmid - unable to parse value of '$key' - $@";
2437 $key = 'ide2' if $key eq 'cdrom';
2438 my $fmt = $confdesc->{$key}->{format
};
2439 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2440 my $v = parse_drive
($key, $value);
2441 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2442 $v->{file
} = $volid;
2443 $value = print_drive
($vmid, $v);
2445 warn "vm $vmid - unable to parse value of '$key'\n";
2450 $conf->{$key} = $value;
2455 if (defined($descr)) {
2457 $conf->{description
} = $descr;
2459 delete $res->{snapstate
}; # just to be sure
2464 sub write_vm_config
{
2465 my ($filename, $conf) = @_;
2467 delete $conf->{snapstate
}; # just to be sure
2469 if ($conf->{cdrom
}) {
2470 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2471 $conf->{ide2
} = $conf->{cdrom
};
2472 delete $conf->{cdrom
};
2475 # we do not use 'smp' any longer
2476 if ($conf->{sockets
}) {
2477 delete $conf->{smp
};
2478 } elsif ($conf->{smp
}) {
2479 $conf->{sockets
} = $conf->{smp
};
2480 delete $conf->{cores
};
2481 delete $conf->{smp
};
2484 my $used_volids = {};
2486 my $cleanup_config = sub {
2487 my ($cref, $pending, $snapname) = @_;
2489 foreach my $key (keys %$cref) {
2490 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2491 $key eq 'snapstate' || $key eq 'pending';
2492 my $value = $cref->{$key};
2493 if ($key eq 'delete') {
2494 die "propertry 'delete' is only allowed in [PENDING]\n"
2496 # fixme: check syntax?
2499 eval { $value = check_type
($key, $value); };
2500 die "unable to parse value of '$key' - $@" if $@;
2502 $cref->{$key} = $value;
2504 if (!$snapname && is_valid_drivename
($key)) {
2505 my $drive = parse_drive
($key, $value);
2506 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2511 &$cleanup_config($conf);
2513 &$cleanup_config($conf->{pending
}, 1);
2515 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2516 die "internal error" if $snapname eq 'pending';
2517 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2520 # remove 'unusedX' settings if we re-add a volume
2521 foreach my $key (keys %$conf) {
2522 my $value = $conf->{$key};
2523 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2524 delete $conf->{$key};
2528 my $generate_raw_config = sub {
2529 my ($conf, $pending) = @_;
2533 # add description as comment to top of file
2534 if (defined(my $descr = $conf->{description
})) {
2536 foreach my $cl (split(/\n/, $descr)) {
2537 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2540 $raw .= "#\n" if $pending;
2544 foreach my $key (sort keys %$conf) {
2545 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2546 $raw .= "$key: $conf->{$key}\n";
2551 my $raw = &$generate_raw_config($conf);
2553 if (scalar(keys %{$conf->{pending
}})){
2554 $raw .= "\n[PENDING]\n";
2555 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2558 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2559 $raw .= "\n[$snapname]\n";
2560 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2570 # we use static defaults from our JSON schema configuration
2571 foreach my $key (keys %$confdesc) {
2572 if (defined(my $default = $confdesc->{$key}->{default})) {
2573 $res->{$key} = $default;
2581 my $vmlist = PVE
::Cluster
::get_vmlist
();
2583 return $res if !$vmlist || !$vmlist->{ids
};
2584 my $ids = $vmlist->{ids
};
2586 foreach my $vmid (keys %$ids) {
2587 my $d = $ids->{$vmid};
2588 next if !$d->{node
} || $d->{node
} ne $nodename;
2589 next if !$d->{type
} || $d->{type
} ne 'qemu';
2590 $res->{$vmid}->{exists} = 1;
2595 # test if VM uses local resources (to prevent migration)
2596 sub check_local_resources
{
2597 my ($conf, $noerr) = @_;
2601 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2602 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2604 foreach my $k (keys %$conf) {
2605 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2606 # sockets are safe: they will recreated be on the target side post-migrate
2607 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2608 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2611 die "VM uses local resources\n" if $loc_res && !$noerr;
2616 # check if used storages are available on all nodes (use by migrate)
2617 sub check_storage_availability
{
2618 my ($storecfg, $conf, $node) = @_;
2620 foreach_drive
($conf, sub {
2621 my ($ds, $drive) = @_;
2623 my $volid = $drive->{file
};
2626 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2629 # check if storage is available on both nodes
2630 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2631 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2635 # list nodes where all VM images are available (used by has_feature API)
2637 my ($conf, $storecfg) = @_;
2639 my $nodelist = PVE
::Cluster
::get_nodelist
();
2640 my $nodehash = { map { $_ => 1 } @$nodelist };
2641 my $nodename = PVE
::INotify
::nodename
();
2643 foreach_drive
($conf, sub {
2644 my ($ds, $drive) = @_;
2646 my $volid = $drive->{file
};
2649 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2651 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2652 if ($scfg->{disable
}) {
2654 } elsif (my $avail = $scfg->{nodes
}) {
2655 foreach my $node (keys %$nodehash) {
2656 delete $nodehash->{$node} if !$avail->{$node};
2658 } elsif (!$scfg->{shared
}) {
2659 foreach my $node (keys %$nodehash) {
2660 delete $nodehash->{$node} if $node ne $nodename
2670 my ($pidfile, $pid) = @_;
2672 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2676 return undef if !$line;
2677 my @param = split(/\0/, $line);
2679 my $cmd = $param[0];
2680 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2682 for (my $i = 0; $i < scalar (@param); $i++) {
2685 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2686 my $p = $param[$i+1];
2687 return 1 if $p && ($p eq $pidfile);
2696 my ($vmid, $nocheck, $node) = @_;
2698 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2700 die "unable to find configuration file for VM $vmid - no such machine\n"
2701 if !$nocheck && ! -f
$filename;
2703 my $pidfile = pidfile_name
($vmid);
2705 if (my $fd = IO
::File-
>new("<$pidfile")) {
2710 my $mtime = $st->mtime;
2711 if ($mtime > time()) {
2712 warn "file '$filename' modified in future\n";
2715 if ($line =~ m/^(\d+)$/) {
2717 if (check_cmdline
($pidfile, $pid)) {
2718 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2730 my $vzlist = config_list
();
2732 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2734 while (defined(my $de = $fd->read)) {
2735 next if $de !~ m/^(\d+)\.pid$/;
2737 next if !defined($vzlist->{$vmid});
2738 if (my $pid = check_running
($vmid)) {
2739 $vzlist->{$vmid}->{pid
} = $pid;
2747 my ($storecfg, $conf) = @_;
2749 my $bootdisk = $conf->{bootdisk
};
2750 return undef if !$bootdisk;
2751 return undef if !is_valid_drivename
($bootdisk);
2753 return undef if !$conf->{$bootdisk};
2755 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2756 return undef if !defined($drive);
2758 return undef if drive_is_cdrom
($drive);
2760 my $volid = $drive->{file
};
2761 return undef if !$volid;
2763 return $drive->{size
};
2766 my $last_proc_pid_stat;
2768 # get VM status information
2769 # This must be fast and should not block ($full == false)
2770 # We only query KVM using QMP if $full == true (this can be slow)
2772 my ($opt_vmid, $full) = @_;
2776 my $storecfg = PVE
::Storage
::config
();
2778 my $list = vzlist
();
2779 my $defaults = load_defaults
();
2781 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2783 my $cpucount = $cpuinfo->{cpus
} || 1;
2785 foreach my $vmid (keys %$list) {
2786 next if $opt_vmid && ($vmid ne $opt_vmid);
2788 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2789 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2792 $d->{pid
} = $list->{$vmid}->{pid
};
2794 # fixme: better status?
2795 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2797 my $size = disksize
($storecfg, $conf);
2798 if (defined($size)) {
2799 $d->{disk
} = 0; # no info available
2800 $d->{maxdisk
} = $size;
2806 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2807 * ($conf->{cores
} || $defaults->{cores
});
2808 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2809 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2811 $d->{name
} = $conf->{name
} || "VM $vmid";
2812 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2813 : $defaults->{memory
}*(1024*1024);
2815 if ($conf->{balloon
}) {
2816 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2817 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2818 : $defaults->{shares
};
2829 $d->{diskwrite
} = 0;
2831 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2833 $d->{serial
} = 1 if conf_has_serial
($conf);
2838 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2839 foreach my $dev (keys %$netdev) {
2840 next if $dev !~ m/^tap([1-9]\d*)i/;
2842 my $d = $res->{$vmid};
2845 $d->{netout
} += $netdev->{$dev}->{receive
};
2846 $d->{netin
} += $netdev->{$dev}->{transmit
};
2849 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2850 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2855 my $ctime = gettimeofday
;
2857 foreach my $vmid (keys %$list) {
2859 my $d = $res->{$vmid};
2860 my $pid = $d->{pid
};
2863 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2864 next if !$pstat; # not running
2866 my $used = $pstat->{utime} + $pstat->{stime
};
2868 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2870 if ($pstat->{vsize
}) {
2871 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2874 my $old = $last_proc_pid_stat->{$pid};
2876 $last_proc_pid_stat->{$pid} = {
2884 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2886 if ($dtime > 1000) {
2887 my $dutime = $used - $old->{used
};
2889 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2890 $last_proc_pid_stat->{$pid} = {
2896 $d->{cpu
} = $old->{cpu
};
2900 return $res if !$full;
2902 my $qmpclient = PVE
::QMPClient-
>new();
2904 my $ballooncb = sub {
2905 my ($vmid, $resp) = @_;
2907 my $info = $resp->{'return'};
2908 return if !$info->{max_mem
};
2910 my $d = $res->{$vmid};
2912 # use memory assigned to VM
2913 $d->{maxmem
} = $info->{max_mem
};
2914 $d->{balloon
} = $info->{actual
};
2916 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2917 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2918 $d->{freemem
} = $info->{free_mem
};
2921 $d->{ballooninfo
} = $info;
2924 my $blockstatscb = sub {
2925 my ($vmid, $resp) = @_;
2926 my $data = $resp->{'return'} || [];
2927 my $totalrdbytes = 0;
2928 my $totalwrbytes = 0;
2930 for my $blockstat (@$data) {
2931 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2932 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2934 $blockstat->{device
} =~ s/drive-//;
2935 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2937 $res->{$vmid}->{diskread
} = $totalrdbytes;
2938 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2941 my $statuscb = sub {
2942 my ($vmid, $resp) = @_;
2944 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2945 # this fails if ballon driver is not loaded, so this must be
2946 # the last commnand (following command are aborted if this fails).
2947 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2949 my $status = 'unknown';
2950 if (!defined($status = $resp->{'return'}->{status
})) {
2951 warn "unable to get VM status\n";
2955 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2958 foreach my $vmid (keys %$list) {
2959 next if $opt_vmid && ($vmid ne $opt_vmid);
2960 next if !$res->{$vmid}->{pid
}; # not running
2961 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2964 $qmpclient->queue_execute(undef, 2);
2966 foreach my $vmid (keys %$list) {
2967 next if $opt_vmid && ($vmid ne $opt_vmid);
2968 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2975 my ($conf, $func, @param) = @_;
2977 foreach my $ds (valid_drive_names
()) {
2978 next if !defined($conf->{$ds});
2980 my $drive = parse_drive
($ds, $conf->{$ds});
2983 &$func($ds, $drive, @param);
2988 my ($conf, $func, @param) = @_;
2992 my $test_volid = sub {
2993 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
2997 $volhash->{$volid}->{cdrom
} //= 1;
2998 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3000 $volhash->{$volid}->{replicate
} //= 0;
3001 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3003 $volhash->{$volid}->{shared
} //= 0;
3004 $volhash->{$volid}->{shared
} = 1 if $shared;
3006 $volhash->{$volid}->{referenced_in_config
} //= 0;
3007 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3009 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3010 if defined($snapname);
3013 foreach_drive
($conf, sub {
3014 my ($ds, $drive) = @_;
3015 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3018 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3019 my $snap = $conf->{snapshots
}->{$snapname};
3020 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3021 foreach_drive
($snap, sub {
3022 my ($ds, $drive) = @_;
3023 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3027 foreach my $volid (keys %$volhash) {
3028 &$func($volid, $volhash->{$volid}, @param);
3032 sub conf_has_serial
{
3035 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3036 if ($conf->{"serial$i"}) {
3044 sub vga_conf_has_spice
{
3047 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3052 sub config_to_command
{
3053 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3056 my $globalFlags = [];
3057 my $machineFlags = [];
3063 my $kvmver = kvm_user_version
();
3064 my $vernum = 0; # unknown
3065 my $ostype = $conf->{ostype
};
3066 my $winversion = windows_version
($ostype);
3067 my $kvm = $conf->{kvm
} // 1;
3069 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3071 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3072 $vernum = $1*1000000+$2*1000;
3073 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3074 $vernum = $1*1000000+$2*1000+$3;
3077 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3079 my $have_ovz = -f
'/proc/vz/vestat';
3081 my $q35 = machine_type_is_q35
($conf);
3082 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3083 my $machine_type = $forcemachine || $conf->{machine
};
3084 my $use_old_bios_files = undef;
3085 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3087 my $cpuunits = defined($conf->{cpuunits
}) ?
3088 $conf->{cpuunits
} : $defaults->{cpuunits
};
3090 push @$cmd, '/usr/bin/kvm';
3092 push @$cmd, '-id', $vmid;
3094 my $vmname = $conf->{name
} || "vm$vmid";
3096 push @$cmd, '-name', $vmname;
3100 my $qmpsocket = qmp_socket
($vmid);
3101 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3102 push @$cmd, '-mon', "chardev=qmp,mode=control";
3105 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3107 push @$cmd, '-daemonize';
3109 if ($conf->{smbios1
}) {
3110 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3113 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3114 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3118 if (my $efidisk = $conf->{efidisk0
}) {
3119 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3120 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3121 $format = $d->{format
};
3123 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3124 if (!defined($format)) {
3125 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3126 $format = qemu_img_format
($scfg, $volname);
3130 die "efidisk format must be specified\n"
3131 if !defined($format);
3134 warn "no efidisk configured! Using temporary efivars disk.\n";
3135 $path = "/tmp/$vmid-ovmf.fd";
3136 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3140 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3141 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3145 # add usb controllers
3146 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3147 push @$devices, @usbcontrollers if @usbcontrollers;
3148 my $vga = $conf->{vga
};
3150 my $qxlnum = vga_conf_has_spice
($vga);
3151 $vga = 'qxl' if $qxlnum;
3154 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3155 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3157 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3161 # enable absolute mouse coordinates (needed by vnc)
3163 if (defined($conf->{tablet
})) {
3164 $tablet = $conf->{tablet
};
3166 $tablet = $defaults->{tablet
};
3167 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3168 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3171 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3174 my $gpu_passthrough;
3177 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3178 my $d = parse_hostpci
($conf->{"hostpci$i"});
3181 my $pcie = $d->{pcie
};
3183 die "q35 machine model is not enabled" if !$q35;
3184 $pciaddr = print_pcie_addr
("hostpci$i");
3186 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3189 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3190 my $romfile = $d->{romfile
};
3193 if ($d->{'x-vga'}) {
3194 $xvga = ',x-vga=on';
3197 $gpu_passthrough = 1;
3199 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3203 my $pcidevices = $d->{pciid
};
3204 my $multifunction = 1 if @$pcidevices > 1;
3207 foreach my $pcidevice (@$pcidevices) {
3209 my $id = "hostpci$i";
3210 $id .= ".$j" if $multifunction;
3211 my $addr = $pciaddr;
3212 $addr .= ".$j" if $multifunction;
3213 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3216 $devicestr .= "$rombar$xvga";
3217 $devicestr .= ",multifunction=on" if $multifunction;
3218 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3221 push @$devices, '-device', $devicestr;
3227 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3228 push @$devices, @usbdevices if @usbdevices;
3230 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3231 if (my $path = $conf->{"serial$i"}) {
3232 if ($path eq 'socket') {
3233 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3234 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3235 push @$devices, '-device', "isa-serial,chardev=serial$i";
3237 die "no such serial device\n" if ! -c
$path;
3238 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3239 push @$devices, '-device', "isa-serial,chardev=serial$i";
3245 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3246 if (my $path = $conf->{"parallel$i"}) {
3247 die "no such parallel device\n" if ! -c
$path;
3248 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3249 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3250 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3256 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3257 $sockets = $conf->{sockets
} if $conf->{sockets
};
3259 my $cores = $conf->{cores
} || 1;
3261 my $maxcpus = $sockets * $cores;
3263 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3265 my $allowed_vcpus = $cpuinfo->{cpus
};
3267 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3268 if ($allowed_vcpus < $maxcpus);
3270 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3272 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3273 for (my $i = 2; $i <= $vcpus; $i++) {
3274 my $cpustr = print_cpu_device
($conf,$i);
3275 push @$cmd, '-device', $cpustr;
3280 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3282 push @$cmd, '-nodefaults';
3284 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3286 my $bootindex_hash = {};
3288 foreach my $o (split(//, $bootorder)) {
3289 $bootindex_hash->{$o} = $i*100;
3293 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3295 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3297 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3299 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3301 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3302 my $socket = vnc_socket
($vmid);
3303 push @$cmd, '-vnc', "unix:$socket,x509,password";
3305 push @$cmd, '-nographic';
3309 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3311 my $useLocaltime = $conf->{localtime};
3313 if ($winversion >= 5) { # windows
3314 $useLocaltime = 1 if !defined($conf->{localtime});
3316 # use time drift fix when acpi is enabled
3317 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3318 $tdf = 1 if !defined($conf->{tdf
});
3322 if ($winversion >= 6) {
3323 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3324 push @$cmd, '-no-hpet';
3327 push @$rtcFlags, 'driftfix=slew' if $tdf;
3330 push @$machineFlags, 'accel=tcg';
3333 if ($machine_type) {
3334 push @$machineFlags, "type=${machine_type}";
3337 if ($conf->{startdate
}) {
3338 push @$rtcFlags, "base=$conf->{startdate}";
3339 } elsif ($useLocaltime) {
3340 push @$rtcFlags, 'base=localtime';
3343 my $cpu = $kvm ?
"kvm64" : "qemu64";
3344 if (my $cputype = $conf->{cpu
}) {
3345 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3346 or die "Cannot parse cpu description: $cputype\n";
3347 $cpu = $cpuconf->{cputype
};
3348 $kvm_off = 1 if $cpuconf->{hidden
};
3350 if (defined(my $flags = $cpuconf->{flags
})) {
3351 push @$cpuFlags, split(";", $flags);
3355 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3357 push @$cpuFlags , '-x2apic'
3358 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3360 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3362 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3364 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3366 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3367 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3370 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3372 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3374 push @$cpuFlags, 'kvm=off' if $kvm_off;
3376 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3377 die "internal error"; # should not happen
3379 push @$cpuFlags, "vendor=${cpu_vendor}"
3380 if $cpu_vendor ne 'default';
3382 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3384 push @$cmd, '-cpu', $cpu;
3386 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3388 push @$cmd, '-S' if $conf->{freeze
};
3390 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3393 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3394 #push @$cmd, '-soundhw', 'es1370';
3395 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3397 if($conf->{agent
}) {
3398 my $qgasocket = qmp_socket
($vmid, 1);
3399 my $pciaddr = print_pci_addr
("qga0", $bridges);
3400 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3401 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3402 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3410 for(my $i = 1; $i < $qxlnum; $i++){
3411 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3412 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3415 # assume other OS works like Linux
3416 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3417 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3421 my $pciaddr = print_pci_addr
("spice", $bridges);
3423 my $nodename = PVE
::INotify
::nodename
();
3424 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3425 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3426 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3427 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3428 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3430 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3432 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3433 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3434 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3437 # enable balloon by default, unless explicitly disabled
3438 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3439 $pciaddr = print_pci_addr
("balloon0", $bridges);
3440 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3443 if ($conf->{watchdog
}) {
3444 my $wdopts = parse_watchdog
($conf->{watchdog
});
3445 $pciaddr = print_pci_addr
("watchdog", $bridges);
3446 my $watchdog = $wdopts->{model
} || 'i6300esb';
3447 push @$devices, '-device', "$watchdog$pciaddr";
3448 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3452 my $scsicontroller = {};
3453 my $ahcicontroller = {};
3454 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3456 # Add iscsi initiator name if available
3457 if (my $initiator = get_initiator_name
()) {
3458 push @$devices, '-iscsi', "initiator-name=$initiator";
3461 foreach_drive
($conf, sub {
3462 my ($ds, $drive) = @_;
3464 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3465 push @$vollist, $drive->{file
};
3468 # ignore efidisk here, already added in bios/fw handling code above
3469 return if $drive->{interface
} eq 'efidisk';
3471 $use_virtio = 1 if $ds =~ m/^virtio/;
3473 if (drive_is_cdrom
($drive)) {
3474 if ($bootindex_hash->{d
}) {
3475 $drive->{bootindex
} = $bootindex_hash->{d
};
3476 $bootindex_hash->{d
} += 1;
3479 if ($bootindex_hash->{c
}) {
3480 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3481 $bootindex_hash->{c
} += 1;
3485 if($drive->{interface
} eq 'virtio'){
3486 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3489 if ($drive->{interface
} eq 'scsi') {
3491 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3493 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3494 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3497 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3498 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3499 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3500 } elsif ($drive->{iothread
}) {
3501 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3505 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3506 $queues = ",num_queues=$drive->{queues}";
3509 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3510 $scsicontroller->{$controller}=1;
3513 if ($drive->{interface
} eq 'sata') {
3514 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3515 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3516 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3517 $ahcicontroller->{$controller}=1;
3520 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3521 push @$devices, '-drive',$drive_cmd;
3522 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3525 for (my $i = 0; $i < $MAX_NETS; $i++) {
3526 next if !$conf->{"net$i"};
3527 my $d = parse_net
($conf->{"net$i"});
3530 $use_virtio = 1 if $d->{model
} eq 'virtio';
3532 if ($bootindex_hash->{n
}) {
3533 $d->{bootindex
} = $bootindex_hash->{n
};
3534 $bootindex_hash->{n
} += 1;
3537 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3538 push @$devices, '-netdev', $netdevfull;
3540 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3541 push @$devices, '-device', $netdevicefull;
3546 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3551 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3553 while (my ($k, $v) = each %$bridges) {
3554 $pciaddr = print_pci_addr
("pci.$k");
3555 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3560 if ($conf->{args
}) {
3561 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3565 push @$cmd, @$devices;
3566 push @$cmd, '-rtc', join(',', @$rtcFlags)
3567 if scalar(@$rtcFlags);
3568 push @$cmd, '-machine', join(',', @$machineFlags)
3569 if scalar(@$machineFlags);
3570 push @$cmd, '-global', join(',', @$globalFlags)
3571 if scalar(@$globalFlags);
3573 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3578 return "${var_run_tmpdir}/$vmid.vnc";
3584 my $res = vm_mon_cmd
($vmid, 'query-spice');
3586 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3590 my ($vmid, $qga) = @_;
3591 my $sockettype = $qga ?
'qga' : 'qmp';
3592 return "${var_run_tmpdir}/$vmid.$sockettype";
3597 return "${var_run_tmpdir}/$vmid.pid";
3600 sub vm_devices_list
{
3603 my $res = vm_mon_cmd
($vmid, 'query-pci');
3604 my $devices_to_check = [];
3606 foreach my $pcibus (@$res) {
3607 push @$devices_to_check, @{$pcibus->{devices
}},
3610 while (@$devices_to_check) {
3612 for my $d (@$devices_to_check) {
3613 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3614 next if !$d->{'pci_bridge'};
3616 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3617 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3619 $devices_to_check = $to_check;
3622 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3623 foreach my $block (@$resblock) {
3624 if($block->{device
} =~ m/^drive-(\S+)/){
3629 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3630 foreach my $mice (@$resmice) {
3631 if ($mice->{name
} eq 'QEMU HID Tablet') {
3632 $devices->{tablet
} = 1;
3637 # for usb devices there is no query-usb
3638 # but we can iterate over the entries in
3639 # qom-list path=/machine/peripheral
3640 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3641 foreach my $per (@$resperipheral) {
3642 if ($per->{name
} =~ m/^usb\d+$/) {
3643 $devices->{$per->{name
}} = 1;
3651 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3653 my $q35 = machine_type_is_q35
($conf);
3655 my $devices_list = vm_devices_list
($vmid);
3656 return 1 if defined($devices_list->{$deviceid});
3658 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3660 if ($deviceid eq 'tablet') {
3662 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3664 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3666 die "usb hotplug currently not reliable\n";
3667 # since we can't reliably hot unplug all added usb devices
3668 # and usb passthrough disables live migration
3669 # we disable usb hotplugging for now
3670 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3672 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3674 qemu_iothread_add
($vmid, $deviceid, $device);
3676 qemu_driveadd
($storecfg, $vmid, $device);
3677 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3679 qemu_deviceadd
($vmid, $devicefull);
3680 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3682 eval { qemu_drivedel
($vmid, $deviceid); };
3687 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3690 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3691 my $pciaddr = print_pci_addr
($deviceid);
3692 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3694 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3696 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3697 qemu_iothread_add
($vmid, $deviceid, $device);
3698 $devicefull .= ",iothread=iothread-$deviceid";
3701 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3702 $devicefull .= ",num_queues=$device->{queues}";
3705 qemu_deviceadd
($vmid, $devicefull);
3706 qemu_deviceaddverify
($vmid, $deviceid);
3708 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3710 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3711 qemu_driveadd
($storecfg, $vmid, $device);
3713 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3714 eval { qemu_deviceadd
($vmid, $devicefull); };
3716 eval { qemu_drivedel
($vmid, $deviceid); };
3721 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3723 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3725 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3726 my $use_old_bios_files = undef;
3727 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3729 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3730 qemu_deviceadd
($vmid, $netdevicefull);
3731 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3733 eval { qemu_netdevdel
($vmid, $deviceid); };
3738 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3741 my $pciaddr = print_pci_addr
($deviceid);
3742 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3744 qemu_deviceadd
($vmid, $devicefull);
3745 qemu_deviceaddverify
($vmid, $deviceid);
3748 die "can't hotplug device '$deviceid'\n";
3754 # fixme: this should raise exceptions on error!
3755 sub vm_deviceunplug
{
3756 my ($vmid, $conf, $deviceid) = @_;
3758 my $devices_list = vm_devices_list
($vmid);
3759 return 1 if !defined($devices_list->{$deviceid});
3761 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3763 if ($deviceid eq 'tablet') {
3765 qemu_devicedel
($vmid, $deviceid);
3767 } elsif ($deviceid =~ m/^usb\d+$/) {
3769 die "usb hotplug currently not reliable\n";
3770 # when unplugging usb devices this way,
3771 # there may be remaining usb controllers/hubs
3772 # so we disable it for now
3773 qemu_devicedel
($vmid, $deviceid);
3774 qemu_devicedelverify
($vmid, $deviceid);
3776 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3778 qemu_devicedel
($vmid, $deviceid);
3779 qemu_devicedelverify
($vmid, $deviceid);
3780 qemu_drivedel
($vmid, $deviceid);
3781 qemu_iothread_del
($conf, $vmid, $deviceid);
3783 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3785 qemu_devicedel
($vmid, $deviceid);
3786 qemu_devicedelverify
($vmid, $deviceid);
3787 qemu_iothread_del
($conf, $vmid, $deviceid);
3789 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3791 qemu_devicedel
($vmid, $deviceid);
3792 qemu_drivedel
($vmid, $deviceid);
3793 qemu_deletescsihw
($conf, $vmid, $deviceid);
3795 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3797 qemu_devicedel
($vmid, $deviceid);
3798 qemu_devicedelverify
($vmid, $deviceid);
3799 qemu_netdevdel
($vmid, $deviceid);
3802 die "can't unplug device '$deviceid'\n";
3808 sub qemu_deviceadd
{
3809 my ($vmid, $devicefull) = @_;
3811 $devicefull = "driver=".$devicefull;
3812 my %options = split(/[=,]/, $devicefull);
3814 vm_mon_cmd
($vmid, "device_add" , %options);
3817 sub qemu_devicedel
{
3818 my ($vmid, $deviceid) = @_;
3820 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3823 sub qemu_iothread_add
{
3824 my($vmid, $deviceid, $device) = @_;
3826 if ($device->{iothread
}) {
3827 my $iothreads = vm_iothreads_list
($vmid);
3828 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3832 sub qemu_iothread_del
{
3833 my($conf, $vmid, $deviceid) = @_;
3835 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3836 if ($device->{iothread
}) {
3837 my $iothreads = vm_iothreads_list
($vmid);
3838 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3842 sub qemu_objectadd
{
3843 my($vmid, $objectid, $qomtype) = @_;
3845 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3850 sub qemu_objectdel
{
3851 my($vmid, $objectid) = @_;
3853 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3859 my ($storecfg, $vmid, $device) = @_;
3861 my $drive = print_drive_full
($storecfg, $vmid, $device);
3862 $drive =~ s/\\/\\\\/g;
3863 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3865 # If the command succeeds qemu prints: "OK
"
3866 return 1 if $ret =~ m/OK/s;
3868 die "adding drive failed
: $ret\n";
3872 my($vmid, $deviceid) = @_;
3874 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3877 return 1 if $ret eq "";
3879 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3880 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3882 die "deleting drive
$deviceid failed
: $ret\n";
3885 sub qemu_deviceaddverify {
3886 my ($vmid, $deviceid) = @_;
3888 for (my $i = 0; $i <= 5; $i++) {
3889 my $devices_list = vm_devices_list($vmid);
3890 return 1 if defined($devices_list->{$deviceid});
3894 die "error on hotplug device
'$deviceid'\n";
3898 sub qemu_devicedelverify {
3899 my ($vmid, $deviceid) = @_;
3901 # need to verify that the device is correctly removed as device_del
3902 # is async and empty return is not reliable
3904 for (my $i = 0; $i <= 5; $i++) {
3905 my $devices_list = vm_devices_list($vmid);
3906 return 1 if !defined($devices_list->{$deviceid});
3910 die "error on hot-unplugging device
'$deviceid'\n";
3913 sub qemu_findorcreatescsihw {
3914 my ($storecfg, $conf, $vmid, $device) = @_;
3916 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3918 my $scsihwid="$controller_prefix$controller";
3919 my $devices_list = vm_devices_list($vmid);
3921 if(!defined($devices_list->{$scsihwid})) {
3922 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3928 sub qemu_deletescsihw {
3929 my ($conf, $vmid, $opt) = @_;
3931 my $device = parse_drive($opt, $conf->{$opt});
3933 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3934 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3938 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3940 my $devices_list = vm_devices_list($vmid);
3941 foreach my $opt (keys %{$devices_list}) {
3942 if (PVE::QemuServer::is_valid_drivename($opt)) {
3943 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3944 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3950 my $scsihwid="scsihw
$controller";
3952 vm_deviceunplug($vmid, $conf, $scsihwid);
3957 sub qemu_add_pci_bridge {
3958 my ($storecfg, $conf, $vmid, $device) = @_;
3964 print_pci_addr($device, $bridges);
3966 while (my ($k, $v) = each %$bridges) {
3969 return 1 if !defined($bridgeid) || $bridgeid < 1;
3971 my $bridge = "pci
.$bridgeid";
3972 my $devices_list = vm_devices_list($vmid);
3974 if (!defined($devices_list->{$bridge})) {
3975 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3981 sub qemu_set_link_status {
3982 my ($vmid, $device, $up) = @_;
3984 vm_mon_cmd($vmid, "set_link
", name => $device,
3985 up => $up ? JSON::true : JSON::false);
3988 sub qemu_netdevadd {
3989 my ($vmid, $conf, $device, $deviceid) = @_;
3991 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3992 my %options = split(/[=,]/, $netdev);
3994 vm_mon_cmd($vmid, "netdev_add
", %options);
3998 sub qemu_netdevdel {
3999 my ($vmid, $deviceid) = @_;
4001 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4004 sub qemu_usb_hotplug {
4005 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4009 # remove the old one first
4010 vm_deviceunplug($vmid, $conf, $deviceid);
4012 # check if xhci controller is necessary and available
4013 if ($device->{usb3}) {
4015 my $devicelist = vm_devices_list($vmid);
4017 if (!$devicelist->{xhci}) {
4018 my $pciaddr = print_pci_addr("xhci
");
4019 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4022 my $d = parse_usb_device($device->{host});
4023 $d->{usb3} = $device->{usb3};
4026 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4029 sub qemu_cpu_hotplug {
4030 my ($vmid, $conf, $vcpus) = @_;
4032 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4035 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4036 $sockets = $conf->{sockets} if $conf->{sockets};
4037 my $cores = $conf->{cores} || 1;
4038 my $maxcpus = $sockets * $cores;
4040 $vcpus = $maxcpus if !$vcpus;
4042 die "you can
't add more vcpus than maxcpus\n"
4043 if $vcpus > $maxcpus;
4045 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4047 if ($vcpus < $currentvcpus) {
4049 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4051 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4052 qemu_devicedel($vmid, "cpu$i");
4054 my $currentrunningvcpus = undef;
4056 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4057 last if scalar(@{$currentrunningvcpus}) == $i-1;
4058 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4062 #update conf after each succesfull cpu unplug
4063 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4064 PVE::QemuConfig->write_config($vmid, $conf);
4067 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4073 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4074 die "vcpus in running vm does not match its configuration\n"
4075 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4077 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4079 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4080 my $cpustr = print_cpu_device($conf, $i);
4081 qemu_deviceadd($vmid, $cpustr);
4084 my $currentrunningvcpus = undef;
4086 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4087 last if scalar(@{$currentrunningvcpus}) == $i;
4088 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4092 #update conf after each succesfull cpu hotplug
4093 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4094 PVE::QemuConfig->write_config($vmid, $conf);
4098 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4099 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4104 sub qemu_block_set_io_throttle {
4105 my ($vmid, $deviceid,
4106 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4107 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4108 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4109 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4111 return if !check_running($vmid) ;
4113 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4115 bps_rd => int($bps_rd),
4116 bps_wr => int($bps_wr),
4118 iops_rd => int($iops_rd),
4119 iops_wr => int($iops_wr),
4120 bps_max => int($bps_max),
4121 bps_rd_max => int($bps_rd_max),
4122 bps_wr_max => int($bps_wr_max),
4123 iops_max => int($iops_max),
4124 iops_rd_max => int($iops_rd_max),
4125 iops_wr_max => int($iops_wr_max),
4126 bps_max_length => int($bps_max_length),
4127 bps_rd_max_length => int($bps_rd_max_length),
4128 bps_wr_max_length => int($bps_wr_max_length),
4129 iops_max_length => int($iops_max_length),
4130 iops_rd_max_length => int($iops_rd_max_length),
4131 iops_wr_max_length => int($iops_wr_max_length),
4136 # old code, only used to shutdown old VM after update
4138 my ($fh, $timeout) = @_;
4140 my $sel = new IO::Select;
4147 while (scalar (@ready = $sel->can_read($timeout))) {
4149 if ($count = $fh->sysread($buf, 8192)) {
4150 if ($buf =~ /^(.*)\(qemu\) $/s) {
4157 if (!defined($count)) {
4164 die "monitor read timeout\n" if !scalar(@ready);
4169 sub qemu_block_resize {
4170 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4172 my $running = check_running($vmid);
4174 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4176 return if !$running;
4178 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4182 sub qemu_volume_snapshot {
4183 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4185 my $running = check_running($vmid);
4187 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4188 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4190 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4194 sub qemu_volume_snapshot_delete {
4195 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4197 my $running = check_running($vmid);
4199 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4200 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4202 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4206 sub set_migration_caps {
4212 "auto-converge" => 1,
4214 "x-rdma-pin-all" => 0,
4219 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4221 for my $supported_capability (@$supported_capabilities) {
4223 capability => $supported_capability->{capability},
4224 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4228 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4231 my $fast_plug_option = {
4239 'vmstatestorage
' => 1,
4242 # hotplug changes in [PENDING]
4243 # $selection hash can be used to only apply specified options, for
4244 # example: { cores => 1 } (only apply changed 'cores
')
4245 # $errors ref is used to return error messages
4246 sub vmconfig_hotplug_pending {
4247 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4249 my $defaults = load_defaults();
4251 # commit values which do not have any impact on running VM first
4252 # Note: those option cannot raise errors, we we do not care about
4253 # $selection and always apply them.
4255 my $add_error = sub {
4256 my ($opt, $msg) = @_;
4257 $errors->{$opt} = "hotplug problem - $msg";
4261 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4262 if ($fast_plug_option->{$opt}) {
4263 $conf->{$opt} = $conf->{pending}->{$opt};
4264 delete $conf->{pending}->{$opt};
4270 PVE::QemuConfig->write_config($vmid, $conf);
4271 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4274 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4276 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4277 while (my ($opt, $force) = each %$pending_delete_hash) {
4278 next if $selection && !$selection->{$opt};
4280 if ($opt eq 'hotplug
') {
4281 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4282 } elsif ($opt eq 'tablet
') {
4283 die "skip\n" if !$hotplug_features->{usb};
4284 if ($defaults->{tablet}) {
4285 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4287 vm_deviceunplug($vmid, $conf, $opt);
4289 } elsif ($opt =~ m/^usb\d+/) {
4291 # since we cannot reliably hot unplug usb devices
4292 # we are disabling it
4293 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4294 vm_deviceunplug($vmid, $conf, $opt);
4295 } elsif ($opt eq 'vcpus
') {
4296 die "skip\n" if !$hotplug_features->{cpu};
4297 qemu_cpu_hotplug($vmid, $conf, undef);
4298 } elsif ($opt eq 'balloon
') {
4299 # enable balloon device is not hotpluggable
4300 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4301 # here we reset the ballooning value to memory
4302 my $balloon = $conf->{memory} || $defaults->{memory};
4303 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4304 } elsif ($fast_plug_option->{$opt}) {
4306 } elsif ($opt =~ m/^net(\d+)$/) {
4307 die "skip\n" if !$hotplug_features->{network};
4308 vm_deviceunplug($vmid, $conf, $opt);
4309 } elsif (is_valid_drivename($opt)) {
4310 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4311 vm_deviceunplug($vmid, $conf, $opt);
4312 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4313 } elsif ($opt =~ m/^memory$/) {
4314 die "skip\n" if !$hotplug_features->{memory};
4315 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4316 } elsif ($opt eq 'cpuunits
') {
4317 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4318 } elsif ($opt eq 'cpulimit
') {
4319 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4325 &$add_error($opt, $err) if $err ne "skip\n";
4327 # save new config if hotplug was successful
4328 delete $conf->{$opt};
4329 vmconfig_undelete_pending_option($conf, $opt);
4330 PVE::QemuConfig->write_config($vmid, $conf);
4331 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4335 my $apply_pending_cloudinit;
4336 $apply_pending_cloudinit = sub {
4337 my ($key, $value) = @_;
4338 $apply_pending_cloudinit = sub {}; # once is enough
4340 my @cloudinit_opts = keys %$confdesc_cloudinit;
4341 foreach my $opt (keys %{$conf->{pending}}) {
4342 next if !grep { $_ eq $opt } @cloudinit_opts;
4343 $conf->{$opt} = delete $conf->{pending}->{$opt};
4346 my $new_conf = { %$conf };
4347 $new_conf->{$key} = $value;
4348 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4351 foreach my $opt (keys %{$conf->{pending}}) {
4352 next if $selection && !$selection->{$opt};
4353 my $value = $conf->{pending}->{$opt};
4355 if ($opt eq 'hotplug
') {
4356 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4357 } elsif ($opt eq 'tablet
') {
4358 die "skip\n" if !$hotplug_features->{usb};
4360 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4361 } elsif ($value == 0) {
4362 vm_deviceunplug($vmid, $conf, $opt);
4364 } elsif ($opt =~ m/^usb\d+$/) {
4366 # since we cannot reliably hot unplug usb devices
4367 # we are disabling it
4368 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4369 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4370 die "skip\n" if !$d;
4371 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4372 } elsif ($opt eq 'vcpus
') {
4373 die "skip\n" if !$hotplug_features->{cpu};
4374 qemu_cpu_hotplug($vmid, $conf, $value);
4375 } elsif ($opt eq 'balloon
') {
4376 # enable/disable balloning device is not hotpluggable
4377 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4378 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4379 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4381 # allow manual ballooning if shares is set to zero
4382 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4383 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4384 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4386 } elsif ($opt =~ m/^net(\d+)$/) {
4387 # some changes can be done without hotplug
4388 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4389 $vmid, $opt, $value);
4390 } elsif (is_valid_drivename($opt)) {
4391 # some changes can be done without hotplug
4392 my $drive = parse_drive($opt, $value);
4393 if (drive_is_cloudinit($drive)) {
4394 &$apply_pending_cloudinit($opt, $value);
4396 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4397 $vmid, $opt, $value, 1);
4398 } elsif ($opt =~ m/^memory$/) { #dimms
4399 die "skip\n" if !$hotplug_features->{memory};
4400 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4401 } elsif ($opt eq 'cpuunits
') {
4402 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4403 } elsif ($opt eq 'cpulimit
') {
4404 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4405 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4407 die "skip\n"; # skip non-hot-pluggable options
4411 &$add_error($opt, $err) if $err ne "skip\n";
4413 # save new config if hotplug was successful
4414 $conf->{$opt} = $value;
4415 delete $conf->{pending}->{$opt};
4416 PVE::QemuConfig->write_config($vmid, $conf);
4417 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4422 sub try_deallocate_drive {
4423 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4425 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4426 my $volid = $drive->{file};
4427 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4428 my $sid = PVE::Storage::parse_volume_id($volid);
4429 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4431 # check if the disk is really unused
4432 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4433 if is_volume_in_use($storecfg, $conf, $key, $volid);
4434 PVE::Storage::vdisk_free($storecfg, $volid);
4437 # If vm is not owner of this disk remove from config
4445 sub vmconfig_delete_or_detach_drive {
4446 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4448 my $drive = parse_drive($opt, $conf->{$opt});
4450 my $rpcenv = PVE::RPCEnvironment::get();
4451 my $authuser = $rpcenv->get_user();
4454 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4455 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4457 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4461 sub vmconfig_apply_pending {
4462 my ($vmid, $conf, $storecfg) = @_;
4466 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4467 while (my ($opt, $force) = each %$pending_delete_hash) {
4468 die "internal error" if $opt =~ m/^unused/;
4469 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4470 if (!defined($conf->{$opt})) {
4471 vmconfig_undelete_pending_option($conf, $opt);
4472 PVE::QemuConfig->write_config($vmid, $conf);
4473 } elsif (is_valid_drivename($opt)) {
4474 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4475 vmconfig_undelete_pending_option($conf, $opt);
4476 delete $conf->{$opt};
4477 PVE::QemuConfig->write_config($vmid, $conf);
4479 vmconfig_undelete_pending_option($conf, $opt);
4480 delete $conf->{$opt};
4481 PVE::QemuConfig->write_config($vmid, $conf);
4485 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4487 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4488 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4490 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4491 # skip if nothing changed
4492 } elsif (is_valid_drivename($opt)) {
4493 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4494 if defined($conf->{$opt});
4495 $conf->{$opt} = $conf->{pending}->{$opt};
4497 $conf->{$opt} = $conf->{pending}->{$opt};
4500 delete $conf->{pending}->{$opt};
4501 PVE::QemuConfig->write_config($vmid, $conf);
4505 my $safe_num_ne = sub {
4508 return 0 if !defined($a) && !defined($b);
4509 return 1 if !defined($a);
4510 return 1 if !defined($b);
4515 my $safe_string_ne = sub {
4518 return 0 if !defined($a) && !defined($b);
4519 return 1 if !defined($a);
4520 return 1 if !defined($b);
4525 sub vmconfig_update_net {
4526 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4528 my $newnet = parse_net($value);
4530 if ($conf->{$opt}) {
4531 my $oldnet = parse_net($conf->{$opt});
4533 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4534 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4535 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4536 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4538 # for non online change, we try to hot-unplug
4539 die "skip\n" if !$hotplug;
4540 vm_deviceunplug($vmid, $conf, $opt);
4543 die "internal error" if $opt !~ m/net(\d+)/;
4544 my $iface = "tap${vmid}i$1";
4546 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4547 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4548 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4549 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4550 PVE::Network::tap_unplug($iface);
4551 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4552 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4553 # Rate can be applied on its own but any change above needs to
4554 # include the rate in tap_plug since OVS resets everything.
4555 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4558 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4559 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4567 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4573 sub vmconfig_update_disk {
4574 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4576 # fixme: do we need force?
4578 my $drive = parse_drive($opt, $value);
4580 if ($conf->{$opt}) {
4582 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4584 my $media = $drive->{media} || 'disk
';
4585 my $oldmedia = $old_drive->{media} || 'disk
';
4586 die "unable to change media type\n" if $media ne $oldmedia;
4588 if (!drive_is_cdrom($old_drive)) {
4590 if ($drive->{file} ne $old_drive->{file}) {
4592 die "skip\n" if !$hotplug;
4594 # unplug and register as unused
4595 vm_deviceunplug($vmid, $conf, $opt);
4596 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4599 # update existing disk
4601 # skip non hotpluggable value
4602 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4603 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4604 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4605 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4610 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4611 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4612 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4613 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4614 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4615 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4616 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4617 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4618 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4619 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4620 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4621 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4622 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4623 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4624 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4625 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4626 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4627 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4629 qemu_block_set_io_throttle($vmid,"drive-$opt",
4630 ($drive->{mbps} || 0)*1024*1024,
4631 ($drive->{mbps_rd} || 0)*1024*1024,
4632 ($drive->{mbps_wr} || 0)*1024*1024,
4633 $drive->{iops} || 0,
4634 $drive->{iops_rd} || 0,
4635 $drive->{iops_wr} || 0,
4636 ($drive->{mbps_max} || 0)*1024*1024,
4637 ($drive->{mbps_rd_max} || 0)*1024*1024,
4638 ($drive->{mbps_wr_max} || 0)*1024*1024,
4639 $drive->{iops_max} || 0,
4640 $drive->{iops_rd_max} || 0,
4641 $drive->{iops_wr_max} || 0,
4642 $drive->{bps_max_length} || 1,
4643 $drive->{bps_rd_max_length} || 1,
4644 $drive->{bps_wr_max_length} || 1,
4645 $drive->{iops_max_length} || 1,
4646 $drive->{iops_rd_max_length} || 1,
4647 $drive->{iops_wr_max_length} || 1);
4656 if ($drive->{file} eq 'none
') {
4657 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4658 if (drive_is_cloudinit($old_drive)) {
4659 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4662 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4663 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4664 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4672 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4674 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4675 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4679 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4680 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4682 PVE::QemuConfig->lock_config($vmid, sub {
4683 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4685 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4687 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4689 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4691 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4692 vmconfig_apply_pending($vmid, $conf, $storecfg);
4693 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4696 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4698 my $defaults = load_defaults();
4700 # set environment variable useful inside network script
4701 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4703 my $local_volumes = {};
4705 if ($targetstorage) {
4706 foreach_drive($conf, sub {
4707 my ($ds, $drive) = @_;
4709 return if drive_is_cdrom($drive);
4711 my $volid = $drive->{file};
4715 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4717 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4718 return if $scfg->{shared};
4719 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4724 foreach my $opt (sort keys %$local_volumes) {
4726 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4727 my $drive = parse_drive($opt, $conf->{$opt});
4729 #if remote storage is specified, use default format
4730 if ($targetstorage && $targetstorage ne "1") {
4731 $storeid = $targetstorage;
4732 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4733 $format = $defFormat;
4735 #else we use same format than original
4736 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4737 $format = qemu_img_format($scfg, $volid);
4740 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4741 my $newdrive = $drive;
4742 $newdrive->{format} = $format;
4743 $newdrive->{file} = $newvolid;
4744 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4745 $local_volumes->{$opt} = $drivestr;
4746 #pass drive to conf for command line
4747 $conf->{$opt} = $drivestr;
4751 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4753 my $migrate_port = 0;
4756 if ($statefile eq 'tcp
') {
4757 my $localip = "localhost";
4758 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4759 my $nodename = PVE::INotify::nodename();
4761 if (!defined($migration_type)) {
4762 if (defined($datacenterconf->{migration}->{type})) {
4763 $migration_type = $datacenterconf->{migration}->{type};
4765 $migration_type = 'secure
';
4769 if ($migration_type eq 'insecure
') {
4770 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4771 if ($migrate_network_addr) {
4772 $localip = $migrate_network_addr;
4774 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4777 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4780 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4781 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4782 $migrate_uri = "tcp:${localip}:${migrate_port}";
4783 push @$cmd, '-incoming
', $migrate_uri;
4786 } elsif ($statefile eq 'unix
') {
4787 # should be default for secure migrations as a ssh TCP forward
4788 # tunnel is not deterministic reliable ready and fails regurarly
4789 # to set up in time, so use UNIX socket forwards
4790 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4791 unlink $socket_addr;
4793 $migrate_uri = "unix:$socket_addr";
4795 push @$cmd, '-incoming
', $migrate_uri;
4799 push @$cmd, '-loadstate
', $statefile;
4806 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4807 my $d = parse_hostpci($conf->{"hostpci$i"});
4809 my $pcidevices = $d->{pciid};
4810 foreach my $pcidevice (@$pcidevices) {
4811 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4813 my $info = pci_device_info("0000:$pciid");
4814 die "IOMMU not present\n" if !check_iommu_support();
4815 die "no pci device info for device '$pciid'\n" if !$info;
4816 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4817 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4821 PVE::Storage::activate_volumes($storecfg, $vollist);
4823 if (!check_running($vmid, 1)) {
4825 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4826 outfunc => sub {}, errfunc => sub {});
4830 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4831 : $defaults->{cpuunits};
4833 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4834 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4837 Slice => 'qemu
.slice
',
4839 CPUShares => $cpuunits
4842 if (my $cpulimit = $conf->{cpulimit}) {
4843 $properties{CPUQuota} = int($cpulimit * 100);
4845 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4847 my $run_qemu = sub {
4848 PVE::Tools::run_fork sub {
4849 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4850 run_command($cmd, %run_params);
4854 if ($conf->{hugepages}) {
4857 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4858 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4860 PVE::QemuServer::Memory::hugepages_mount();
4861 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4863 eval { $run_qemu->() };
4865 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4869 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4871 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4874 eval { $run_qemu->() };
4878 # deactivate volumes if start fails
4879 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4880 die "start failed: $err";
4883 print "migration listens on $migrate_uri\n" if $migrate_uri;
4885 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4886 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4890 #start nbd server for storage migration
4891 if ($targetstorage) {
4892 my $nodename = PVE::INotify::nodename();
4893 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4894 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4895 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4896 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4898 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4900 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4902 foreach my $opt (sort keys %$local_volumes) {
4903 my $volid = $local_volumes->{$opt};
4904 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4905 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4906 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4910 if ($migratedfrom) {
4912 set_migration_caps($vmid);
4917 print "spice listens on port $spice_port\n";
4918 if ($spice_ticket) {
4919 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4920 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4925 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4926 if !$statefile && $conf->{balloon};
4928 foreach my $opt (keys %$conf) {
4929 next if $opt !~ m/^net\d+$/;
4930 my $nicconf = parse_net($conf->{$opt});
4931 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4935 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4936 path => "machine/peripheral/balloon0",
4937 property => "guest-stats-polling-interval",
4938 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4944 my ($vmid, $execute, %params) = @_;
4946 my $cmd = { execute => $execute, arguments => \%params };
4947 vm_qmp_command($vmid, $cmd);
4950 sub vm_mon_cmd_nocheck {
4951 my ($vmid, $execute, %params) = @_;
4953 my $cmd = { execute => $execute, arguments => \%params };
4954 vm_qmp_command($vmid, $cmd, 1);
4957 sub vm_qmp_command {
4958 my ($vmid, $cmd, $nocheck) = @_;
4963 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4964 $timeout = $cmd->{arguments}->{timeout};
4965 delete $cmd->{arguments}->{timeout};
4969 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4970 my $sname = qmp_socket($vmid);
4971 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4972 my $qmpclient = PVE::QMPClient->new();
4974 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4976 die "unable to open monitor socket\n";
4980 syslog("err", "VM $vmid qmp command failed - $err");
4987 sub vm_human_monitor_command {
4988 my ($vmid, $cmdline) = @_;
4993 execute => 'human-monitor-command
',
4994 arguments => { 'command-line
' => $cmdline},
4997 return vm_qmp_command($vmid, $cmd);
5000 sub vm_commandline {
5001 my ($storecfg, $vmid) = @_;
5003 my $conf = PVE::QemuConfig->load_config($vmid);
5005 my $defaults = load_defaults();
5007 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5009 return PVE::Tools::cmd2string($cmd);
5013 my ($vmid, $skiplock) = @_;
5015 PVE::QemuConfig->lock_config($vmid, sub {
5017 my $conf = PVE::QemuConfig->load_config($vmid);
5019 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5021 vm_mon_cmd($vmid, "system_reset");
5025 sub get_vm_volumes {
5029 foreach_volid($conf, sub {
5030 my ($volid, $attr) = @_;
5032 return if $volid =~ m|^/|;
5034 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5037 push @$vollist, $volid;
5043 sub vm_stop_cleanup {
5044 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5049 my $vollist = get_vm_volumes($conf);
5050 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5053 foreach my $ext (qw(mon qmp pid vnc qga)) {
5054 unlink "/var/run/qemu-server/${vmid}.$ext";
5057 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5059 warn $@ if $@; # avoid errors - just warn
5062 # Note: use $nockeck to skip tests if VM configuration file exists.
5063 # We need that when migration VMs to other nodes (files already moved)
5064 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5066 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5068 $force = 1 if !defined($force) && !$shutdown;
5071 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5072 kill 15, $pid if $pid;
5073 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5074 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5078 PVE
::QemuConfig-
>lock_config($vmid, sub {
5080 my $pid = check_running
($vmid, $nocheck);
5085 $conf = PVE
::QemuConfig-
>load_config($vmid);
5086 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5087 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5088 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5089 $timeout = $opts->{down
} if $opts->{down
};
5093 $timeout = 60 if !defined($timeout);
5097 if (defined($conf) && $conf->{agent
}) {
5098 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5100 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5103 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5110 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5115 if ($count >= $timeout) {
5117 warn "VM still running - terminating now with SIGTERM\n";
5120 die "VM quit/powerdown failed - got timeout\n";
5123 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5128 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5131 die "VM quit/powerdown failed\n";
5139 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5144 if ($count >= $timeout) {
5145 warn "VM still running - terminating now with SIGKILL\n";
5150 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5155 my ($vmid, $skiplock) = @_;
5157 PVE
::QemuConfig-
>lock_config($vmid, sub {
5159 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5161 PVE
::QemuConfig-
>check_lock($conf)
5162 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5164 vm_mon_cmd
($vmid, "stop");
5169 my ($vmid, $skiplock, $nocheck) = @_;
5171 PVE
::QemuConfig-
>lock_config($vmid, sub {
5175 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5177 PVE
::QemuConfig-
>check_lock($conf)
5178 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5180 vm_mon_cmd
($vmid, "cont");
5183 vm_mon_cmd_nocheck
($vmid, "cont");
5189 my ($vmid, $skiplock, $key) = @_;
5191 PVE
::QemuConfig-
>lock_config($vmid, sub {
5193 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5195 # there is no qmp command, so we use the human monitor command
5196 vm_human_monitor_command
($vmid, "sendkey $key");
5201 my ($storecfg, $vmid, $skiplock) = @_;
5203 PVE
::QemuConfig-
>lock_config($vmid, sub {
5205 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5207 if (!check_running
($vmid)) {
5208 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5210 die "VM $vmid is running - destroy failed\n";
5218 my ($filename, $buf) = @_;
5220 my $fh = IO
::File-
>new($filename, "w");
5221 return undef if !$fh;
5223 my $res = print $fh $buf;
5230 sub pci_device_info
{
5235 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5236 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5238 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5239 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5241 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5242 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5244 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5245 return undef if !defined($product) || $product !~ s/^0x//;
5250 product
=> $product,
5256 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5265 my $name = $dev->{name
};
5267 my $fn = "$pcisysfs/devices/$name/reset";
5269 return file_write
($fn, "1");
5272 sub pci_dev_bind_to_vfio
{
5275 my $name = $dev->{name
};
5277 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5279 if (!-d
$vfio_basedir) {
5280 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5282 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5284 my $testdir = "$vfio_basedir/$name";
5285 return 1 if -d
$testdir;
5287 my $data = "$dev->{vendor} $dev->{product}";
5288 return undef if !file_write
("$vfio_basedir/new_id", $data);
5290 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5291 if (!file_write
($fn, $name)) {
5292 return undef if -f
$fn;
5295 $fn = "$vfio_basedir/bind";
5296 if (! -d
$testdir) {
5297 return undef if !file_write
($fn, $name);
5303 sub pci_dev_group_bind_to_vfio
{
5306 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5308 if (!-d
$vfio_basedir) {
5309 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5311 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5313 # get IOMMU group devices
5314 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5315 my @devs = grep /^0000:/, readdir($D);
5318 foreach my $pciid (@devs) {
5319 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5321 # pci bridges, switches or root ports are not supported
5322 # they have a pci_bus subdirectory so skip them
5323 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5325 my $info = pci_device_info
($1);
5326 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5332 # vzdump restore implementaion
5334 sub tar_archive_read_firstfile
{
5335 my $archive = shift;
5337 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5339 # try to detect archive type first
5340 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5341 die "unable to open file '$archive'\n";
5342 my $firstfile = <$fh>;
5346 die "ERROR: archive contaions no data\n" if !$firstfile;
5352 sub tar_restore_cleanup
{
5353 my ($storecfg, $statfile) = @_;
5355 print STDERR
"starting cleanup\n";
5357 if (my $fd = IO
::File-
>new($statfile, "r")) {
5358 while (defined(my $line = <$fd>)) {
5359 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5362 if ($volid =~ m
|^/|) {
5363 unlink $volid || die 'unlink failed\n';
5365 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5367 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5369 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5371 print STDERR
"unable to parse line in statfile - $line";
5378 sub restore_archive
{
5379 my ($archive, $vmid, $user, $opts) = @_;
5381 my $format = $opts->{format
};
5384 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5385 $format = 'tar' if !$format;
5387 } elsif ($archive =~ m/\.tar$/) {
5388 $format = 'tar' if !$format;
5389 } elsif ($archive =~ m/.tar.lzo$/) {
5390 $format = 'tar' if !$format;
5392 } elsif ($archive =~ m/\.vma$/) {
5393 $format = 'vma' if !$format;
5394 } elsif ($archive =~ m/\.vma\.gz$/) {
5395 $format = 'vma' if !$format;
5397 } elsif ($archive =~ m/\.vma\.lzo$/) {
5398 $format = 'vma' if !$format;
5401 $format = 'vma' if !$format; # default
5404 # try to detect archive format
5405 if ($format eq 'tar') {
5406 return restore_tar_archive
($archive, $vmid, $user, $opts);
5408 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5412 sub restore_update_config_line
{
5413 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5415 return if $line =~ m/^\#qmdump\#/;
5416 return if $line =~ m/^\#vzdump\#/;
5417 return if $line =~ m/^lock:/;
5418 return if $line =~ m/^unused\d+:/;
5419 return if $line =~ m/^parent:/;
5420 return if $line =~ m/^template:/; # restored VM is never a template
5422 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5423 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5424 # try to convert old 1.X settings
5425 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5426 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5427 my ($model, $macaddr) = split(/\=/, $devconfig);
5428 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5431 bridge
=> "vmbr$ind",
5432 macaddr
=> $macaddr,
5434 my $netstr = print_net
($net);
5436 print $outfd "net$cookie->{netcount}: $netstr\n";
5437 $cookie->{netcount
}++;
5439 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5440 my ($id, $netstr) = ($1, $2);
5441 my $net = parse_net
($netstr);
5442 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5443 $netstr = print_net
($net);
5444 print $outfd "$id: $netstr\n";
5445 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5448 my $di = parse_drive
($virtdev, $value);
5449 if (defined($di->{backup
}) && !$di->{backup
}) {
5450 print $outfd "#$line";
5451 } elsif ($map->{$virtdev}) {
5452 delete $di->{format
}; # format can change on restore
5453 $di->{file
} = $map->{$virtdev};
5454 $value = print_drive
($vmid, $di);
5455 print $outfd "$virtdev: $value\n";
5459 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5460 my ($uuid, $uuid_str);
5461 UUID
::generate
($uuid);
5462 UUID
::unparse
($uuid, $uuid_str);
5463 my $smbios1 = parse_smbios1
($2);
5464 $smbios1->{uuid
} = $uuid_str;
5465 print $outfd $1.print_smbios1
($smbios1)."\n";
5472 my ($cfg, $vmid) = @_;
5474 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5476 my $volid_hash = {};
5477 foreach my $storeid (keys %$info) {
5478 foreach my $item (@{$info->{$storeid}}) {
5479 next if !($item->{volid
} && $item->{size
});
5480 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5481 $volid_hash->{$item->{volid
}} = $item;
5488 sub is_volume_in_use
{
5489 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5491 my $path = PVE
::Storage
::path
($storecfg, $volid);
5493 my $scan_config = sub {
5494 my ($cref, $snapname) = @_;
5496 foreach my $key (keys %$cref) {
5497 my $value = $cref->{$key};
5498 if (is_valid_drivename
($key)) {
5499 next if $skip_drive && $key eq $skip_drive;
5500 my $drive = parse_drive
($key, $value);
5501 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5502 return 1 if $volid eq $drive->{file
};
5503 if ($drive->{file
} =~ m!^/!) {
5504 return 1 if $drive->{file
} eq $path;
5506 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5508 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5510 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5518 return 1 if &$scan_config($conf);
5522 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5523 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5529 sub update_disksize
{
5530 my ($vmid, $conf, $volid_hash) = @_;
5534 # used and unused disks
5535 my $referenced = {};
5537 # Note: it is allowed to define multiple storages with same path (alias), so
5538 # we need to check both 'volid' and real 'path' (two different volid can point
5539 # to the same path).
5541 my $referencedpath = {};
5544 foreach my $opt (keys %$conf) {
5545 if (is_valid_drivename
($opt)) {
5546 my $drive = parse_drive
($opt, $conf->{$opt});
5547 my $volid = $drive->{file
};
5550 $referenced->{$volid} = 1;
5551 if ($volid_hash->{$volid} &&
5552 (my $path = $volid_hash->{$volid}->{path
})) {
5553 $referencedpath->{$path} = 1;
5556 next if drive_is_cdrom
($drive);
5557 next if !$volid_hash->{$volid};
5559 $drive->{size
} = $volid_hash->{$volid}->{size
};
5560 my $new = print_drive
($vmid, $drive);
5561 if ($new ne $conf->{$opt}) {
5563 $conf->{$opt} = $new;
5568 # remove 'unusedX' entry if volume is used
5569 foreach my $opt (keys %$conf) {
5570 next if $opt !~ m/^unused\d+$/;
5571 my $volid = $conf->{$opt};
5572 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5573 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5575 delete $conf->{$opt};
5578 $referenced->{$volid} = 1;
5579 $referencedpath->{$path} = 1 if $path;
5582 foreach my $volid (sort keys %$volid_hash) {
5583 next if $volid =~ m/vm-$vmid-state-/;
5584 next if $referenced->{$volid};
5585 my $path = $volid_hash->{$volid}->{path
};
5586 next if !$path; # just to be sure
5587 next if $referencedpath->{$path};
5589 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5590 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5597 my ($vmid, $nolock) = @_;
5599 my $cfg = PVE
::Storage
::config
();
5601 my $volid_hash = scan_volids
($cfg, $vmid);
5603 my $updatefn = sub {
5606 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5608 PVE
::QemuConfig-
>check_lock($conf);
5611 foreach my $volid (keys %$volid_hash) {
5612 my $info = $volid_hash->{$volid};
5613 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5616 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5618 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5621 if (defined($vmid)) {
5625 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5628 my $vmlist = config_list
();
5629 foreach my $vmid (keys %$vmlist) {
5633 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5639 sub restore_vma_archive
{
5640 my ($archive, $vmid, $user, $opts, $comp) = @_;
5642 my $readfrom = $archive;
5644 my $cfg = PVE
::Storage
::config
();
5646 my $bwlimit = $opts->{bwlimit
};
5648 my $dbg_cmdstring = '';
5649 my $add_pipe = sub {
5651 push @$commands, $cmd;
5652 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5653 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5658 if ($archive eq '-') {
5661 # If we use a backup from a PVE defined storage we also consider that
5662 # storage's rate limit:
5663 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5664 if (defined($volid)) {
5665 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5666 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5668 print STDERR
"applying read rate limit: $readlimit\n";
5669 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5670 $add_pipe->($cstream);
5677 if ($comp eq 'gzip') {
5678 $cmd = ['zcat', $readfrom];
5679 } elsif ($comp eq 'lzop') {
5680 $cmd = ['lzop', '-d', '-c', $readfrom];
5682 die "unknown compression method '$comp'\n";
5687 my $tmpdir = "/var/tmp/vzdumptmp$$";
5690 # disable interrupts (always do cleanups)
5694 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5696 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5697 POSIX
::mkfifo
($mapfifo, 0600);
5700 my $openfifo = sub {
5701 open($fifofh, '>', $mapfifo) || die $!;
5704 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5711 my $rpcenv = PVE
::RPCEnvironment
::get
();
5713 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5714 my $tmpfn = "$conffile.$$.tmp";
5716 # Note: $oldconf is undef if VM does not exists
5717 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5718 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5722 my $print_devmap = sub {
5723 my $virtdev_hash = {};
5725 my $cfgfn = "$tmpdir/qemu-server.conf";
5727 # we can read the config - that is already extracted
5728 my $fh = IO
::File-
>new($cfgfn, "r") ||
5729 "unable to read qemu-server.conf - $!\n";
5731 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5733 my $pve_firewall_dir = '/etc/pve/firewall';
5734 mkdir $pve_firewall_dir; # make sure the dir exists
5735 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5738 while (defined(my $line = <$fh>)) {
5739 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5740 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5741 die "archive does not contain data for drive '$virtdev'\n"
5742 if !$devinfo->{$devname};
5743 if (defined($opts->{storage
})) {
5744 $storeid = $opts->{storage
} || 'local';
5745 } elsif (!$storeid) {
5748 $format = 'raw' if !$format;
5749 $devinfo->{$devname}->{devname
} = $devname;
5750 $devinfo->{$devname}->{virtdev
} = $virtdev;
5751 $devinfo->{$devname}->{format
} = $format;
5752 $devinfo->{$devname}->{storeid
} = $storeid;
5754 # check permission on storage
5755 my $pool = $opts->{pool
}; # todo: do we need that?
5756 if ($user ne 'root@pam') {
5757 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5760 $storage_limits{$storeid} = $bwlimit;
5762 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5766 foreach my $key (keys %storage_limits) {
5767 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
5769 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
5770 $storage_limits{$key} = $limit * 1024;
5773 foreach my $devname (keys %$devinfo) {
5774 die "found no device mapping information for device '$devname'\n"
5775 if !$devinfo->{$devname}->{virtdev
};
5778 # create empty/temp config
5780 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5781 foreach_drive
($oldconf, sub {
5782 my ($ds, $drive) = @_;
5784 return if drive_is_cdrom
($drive);
5786 my $volid = $drive->{file
};
5788 return if !$volid || $volid =~ m
|^/|;
5790 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5791 return if !$path || !$owner || ($owner != $vmid);
5793 # Note: only delete disk we want to restore
5794 # other volumes will become unused
5795 if ($virtdev_hash->{$ds}) {
5796 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5803 # delete vmstate files
5804 # since after the restore we have no snapshots anymore
5805 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5806 my $snap = $oldconf->{snapshots
}->{$snapname};
5807 if ($snap->{vmstate
}) {
5808 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5817 foreach my $virtdev (sort keys %$virtdev_hash) {
5818 my $d = $virtdev_hash->{$virtdev};
5819 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5820 my $storeid = $d->{storeid
};
5821 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
5824 if (my $limit = $storage_limits{$storeid}) {
5825 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
5828 # test if requested format is supported
5829 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
5830 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5831 $d->{format
} = $defFormat if !$supported;
5833 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
5834 $d->{format
}, undef, $alloc_size);
5835 print STDERR
"new volume ID is '$volid'\n";
5836 $d->{volid
} = $volid;
5837 my $path = PVE
::Storage
::path
($cfg, $volid);
5839 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5841 my $write_zeros = 1;
5842 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5846 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5848 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5849 $map->{$virtdev} = $volid;
5852 $fh->seek(0, 0) || die "seek failed - $!\n";
5854 my $outfd = new IO
::File
($tmpfn, "w") ||
5855 die "unable to write config for VM $vmid\n";
5857 my $cookie = { netcount
=> 0 };
5858 while (defined(my $line = <$fh>)) {
5859 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5872 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5873 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5875 $oldtimeout = alarm($timeout);
5882 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5883 my ($dev_id, $size, $devname) = ($1, $2, $3);
5884 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5885 } elsif ($line =~ m/^CTIME: /) {
5886 # we correctly received the vma config, so we can disable
5887 # the timeout now for disk allocation (set to 10 minutes, so
5888 # that we always timeout if something goes wrong)
5891 print $fifofh "done\n";
5892 my $tmp = $oldtimeout || 0;
5893 $oldtimeout = undef;
5899 print "restore vma archive: $dbg_cmdstring\n";
5900 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5904 alarm($oldtimeout) if $oldtimeout;
5907 foreach my $devname (keys %$devinfo) {
5908 my $volid = $devinfo->{$devname}->{volid
};
5909 push @$vollist, $volid if $volid;
5912 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5920 foreach my $devname (keys %$devinfo) {
5921 my $volid = $devinfo->{$devname}->{volid
};
5924 if ($volid =~ m
|^/|) {
5925 unlink $volid || die 'unlink failed\n';
5927 PVE
::Storage
::vdisk_free
($cfg, $volid);
5929 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5931 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5938 rename($tmpfn, $conffile) ||
5939 die "unable to commit configuration file '$conffile'\n";
5941 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5943 eval { rescan
($vmid, 1); };
5947 sub restore_tar_archive
{
5948 my ($archive, $vmid, $user, $opts) = @_;
5950 if ($archive ne '-') {
5951 my $firstfile = tar_archive_read_firstfile
($archive);
5952 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5953 if $firstfile ne 'qemu-server.conf';
5956 my $storecfg = PVE
::Storage
::config
();
5958 # destroy existing data - keep empty config
5959 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5960 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5962 my $tocmd = "/usr/lib/qemu-server/qmextract";
5964 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5965 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5966 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5967 $tocmd .= ' --info' if $opts->{info
};
5969 # tar option "xf" does not autodetect compression when read from STDIN,
5970 # so we pipe to zcat
5971 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5972 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5974 my $tmpdir = "/var/tmp/vzdumptmp$$";
5977 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5978 local $ENV{VZDUMP_VMID
} = $vmid;
5979 local $ENV{VZDUMP_USER
} = $user;
5981 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5982 my $tmpfn = "$conffile.$$.tmp";
5984 # disable interrupts (always do cleanups)
5988 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
5996 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5998 if ($archive eq '-') {
5999 print "extracting archive from STDIN\n";
6000 run_command
($cmd, input
=> "<&STDIN");
6002 print "extracting archive '$archive'\n";
6006 return if $opts->{info
};
6010 my $statfile = "$tmpdir/qmrestore.stat";
6011 if (my $fd = IO
::File-
>new($statfile, "r")) {
6012 while (defined (my $line = <$fd>)) {
6013 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6014 $map->{$1} = $2 if $1;
6016 print STDERR
"unable to parse line in statfile - $line\n";
6022 my $confsrc = "$tmpdir/qemu-server.conf";
6024 my $srcfd = new IO
::File
($confsrc, "r") ||
6025 die "unable to open file '$confsrc'\n";
6027 my $outfd = new IO
::File
($tmpfn, "w") ||
6028 die "unable to write config for VM $vmid\n";
6030 my $cookie = { netcount
=> 0 };
6031 while (defined (my $line = <$srcfd>)) {
6032 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6044 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6051 rename $tmpfn, $conffile ||
6052 die "unable to commit configuration file '$conffile'\n";
6054 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6056 eval { rescan
($vmid, 1); };
6060 sub foreach_storage_used_by_vm
{
6061 my ($conf, $func) = @_;
6065 foreach_drive
($conf, sub {
6066 my ($ds, $drive) = @_;
6067 return if drive_is_cdrom
($drive);
6069 my $volid = $drive->{file
};
6071 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6072 $sidhash->{$sid} = $sid if $sid;
6075 foreach my $sid (sort keys %$sidhash) {
6080 sub do_snapshots_with_qemu
{
6081 my ($storecfg, $volid) = @_;
6083 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6085 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6086 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6090 if ($volid =~ m/\.(qcow2|qed)$/){
6097 sub qga_check_running
{
6100 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6102 warn "Qemu Guest Agent is not running - $@";
6108 sub template_create
{
6109 my ($vmid, $conf, $disk) = @_;
6111 my $storecfg = PVE
::Storage
::config
();
6113 foreach_drive
($conf, sub {
6114 my ($ds, $drive) = @_;
6116 return if drive_is_cdrom
($drive);
6117 return if $disk && $ds ne $disk;
6119 my $volid = $drive->{file
};
6120 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6122 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6123 $drive->{file
} = $voliddst;
6124 $conf->{$ds} = print_drive
($vmid, $drive);
6125 PVE
::QemuConfig-
>write_config($vmid, $conf);
6129 sub qemu_img_convert
{
6130 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6132 my $storecfg = PVE
::Storage
::config
();
6133 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6134 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6136 if ($src_storeid && $dst_storeid) {
6138 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6140 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6141 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6143 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6144 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6146 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6147 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6150 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6151 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6152 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6153 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6154 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6155 if ($is_zero_initialized) {
6156 push @$cmd, "zeroinit:$dst_path";
6158 push @$cmd, $dst_path;
6163 if($line =~ m/\((\S+)\/100\
%\)/){
6165 my $transferred = int($size * $percent / 100);
6166 my $remaining = $size - $transferred;
6168 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6173 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6175 die "copy failed: $err" if $err;
6179 sub qemu_img_format
{
6180 my ($scfg, $volname) = @_;
6182 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6189 sub qemu_drive_mirror
{
6190 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6192 $jobs = {} if !$jobs;
6196 $jobs->{"drive-$drive"} = {};
6198 if ($dst_volid =~ /^nbd:/) {
6199 $qemu_target = $dst_volid;
6202 my $storecfg = PVE
::Storage
::config
();
6203 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6205 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6207 $format = qemu_img_format
($dst_scfg, $dst_volname);
6209 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6211 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6214 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6215 $opts->{format
} = $format if $format;
6217 print "drive mirror is starting for drive-$drive\n";
6219 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6222 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6223 die "mirroring error: $err";
6226 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6229 sub qemu_drive_mirror_monitor
{
6230 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6233 my $err_complete = 0;
6236 die "storage migration timed out\n" if $err_complete > 300;
6238 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6240 my $running_mirror_jobs = {};
6241 foreach my $stat (@$stats) {
6242 next if $stat->{type
} ne 'mirror';
6243 $running_mirror_jobs->{$stat->{device
}} = $stat;
6246 my $readycounter = 0;
6248 foreach my $job (keys %$jobs) {
6250 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6251 print "$job : finished\n";
6252 delete $jobs->{$job};
6256 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6258 my $busy = $running_mirror_jobs->{$job}->{busy
};
6259 my $ready = $running_mirror_jobs->{$job}->{ready
};
6260 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6261 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6262 my $remaining = $total - $transferred;
6263 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6265 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6268 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6271 last if scalar(keys %$jobs) == 0;
6273 if ($readycounter == scalar(keys %$jobs)) {
6274 print "all mirroring jobs are ready \n";
6275 last if $skipcomplete; #do the complete later
6277 if ($vmiddst && $vmiddst != $vmid) {
6278 my $agent_running = $qga && qga_check_running
($vmid);
6279 if ($agent_running) {
6280 print "freeze filesystem\n";
6281 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6283 print "suspend vm\n";
6284 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6287 # if we clone a disk for a new target vm, we don't switch the disk
6288 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6290 if ($agent_running) {
6291 print "unfreeze filesystem\n";
6292 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6294 print "resume vm\n";
6295 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6301 foreach my $job (keys %$jobs) {
6302 # try to switch the disk if source and destination are on the same guest
6303 print "$job: Completing block job...\n";
6305 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6306 if ($@ =~ m/cannot be completed/) {
6307 print "$job: Block job cannot be completed, try again.\n";
6310 print "$job: Completed successfully.\n";
6311 $jobs->{$job}->{complete
} = 1;
6322 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6323 die "mirroring error: $err";
6328 sub qemu_blockjobs_cancel
{
6329 my ($vmid, $jobs) = @_;
6331 foreach my $job (keys %$jobs) {
6332 print "$job: Cancelling block job\n";
6333 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6334 $jobs->{$job}->{cancel
} = 1;
6338 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6340 my $running_jobs = {};
6341 foreach my $stat (@$stats) {
6342 $running_jobs->{$stat->{device
}} = $stat;
6345 foreach my $job (keys %$jobs) {
6347 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6348 print "$job: Done.\n";
6349 delete $jobs->{$job};
6353 last if scalar(keys %$jobs) == 0;
6360 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6361 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6366 print "create linked clone of drive $drivename ($drive->{file})\n";
6367 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6368 push @$newvollist, $newvolid;
6371 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6372 $storeid = $storage if $storage;
6374 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6375 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6377 print "create full clone of drive $drivename ($drive->{file})\n";
6379 if (drive_is_cloudinit
($drive)) {
6380 $name = "vm-$newvmid-cloudinit";
6381 # cloudinit only supports raw and qcow2 atm:
6382 if ($dst_format eq 'qcow2') {
6384 } elsif ($dst_format ne 'raw') {
6385 die "clone: unhandled format for cloudinit image\n";
6388 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6389 push @$newvollist, $newvolid;
6391 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6393 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6394 if (!$running || $snapname) {
6395 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6398 my $kvmver = get_running_qemu_version
($vmid);
6399 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6400 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6401 if $drive->{iothread
};
6404 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6408 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6411 $disk->{format
} = undef;
6412 $disk->{file
} = $newvolid;
6413 $disk->{size
} = $size;
6418 # this only works if VM is running
6419 sub get_current_qemu_machine
{
6422 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6423 my $res = vm_qmp_command
($vmid, $cmd);
6425 my ($current, $default);
6426 foreach my $e (@$res) {
6427 $default = $e->{name
} if $e->{'is-default'};
6428 $current = $e->{name
} if $e->{'is-current'};
6431 # fallback to the default machine if current is not supported by qemu
6432 return $current || $default || 'pc';
6435 sub get_running_qemu_version
{
6437 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6438 my $res = vm_qmp_command
($vmid, $cmd);
6439 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6442 sub qemu_machine_feature_enabled
{
6443 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6448 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6450 $current_major = $3;
6451 $current_minor = $4;
6453 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6455 $current_major = $1;
6456 $current_minor = $2;
6459 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6464 sub qemu_machine_pxe
{
6465 my ($vmid, $conf, $machine) = @_;
6467 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6469 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6476 sub qemu_use_old_bios_files
{
6477 my ($machine_type) = @_;
6479 return if !$machine_type;
6481 my $use_old_bios_files = undef;
6483 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6485 $use_old_bios_files = 1;
6487 my $kvmver = kvm_user_version
();
6488 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6489 # load new efi bios files on migration. So this hack is required to allow
6490 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6491 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6492 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6495 return ($use_old_bios_files, $machine_type);
6498 sub create_efidisk
{
6499 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6501 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6503 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6504 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6505 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6507 my $path = PVE
::Storage
::path
($storecfg, $volid);
6509 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6511 die "Copying EFI vars image failed: $@" if $@;
6513 return ($volid, $vars_size);
6520 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6521 my (undef, $id, $function) = @_;
6522 my $res = { id
=> $id, function
=> $function};
6523 push @{$devices->{$id}}, $res;
6526 # Entries should be sorted by functions.
6527 foreach my $id (keys %$devices) {
6528 my $dev = $devices->{$id};
6529 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6535 sub vm_iothreads_list
{
6538 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6541 foreach my $iothread (@$res) {
6542 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6549 my ($conf, $drive) = @_;
6553 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6555 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6561 my $controller = int($drive->{index} / $maxdev);
6562 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6564 return ($maxdev, $controller, $controller_prefix);
6567 sub add_hyperv_enlightenments
{
6568 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6570 return if $winversion < 6;
6571 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6573 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6575 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6576 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6577 push @$cpuFlags , 'hv_vapic';
6578 push @$cpuFlags , 'hv_time';
6580 push @$cpuFlags , 'hv_spinlocks=0xffff';
6583 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6584 push @$cpuFlags , 'hv_reset';
6585 push @$cpuFlags , 'hv_vpindex';
6586 push @$cpuFlags , 'hv_runtime';
6589 if ($winversion >= 7) {
6590 push @$cpuFlags , 'hv_relaxed';
6594 sub windows_version
{
6597 return 0 if !$ostype;
6601 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6603 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6605 } elsif ($ostype =~ m/^win(\d+)$/) {
6612 sub resolve_dst_disk_format
{
6613 my ($storecfg, $storeid, $src_volname, $format) = @_;
6614 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6617 # if no target format is specified, use the source disk format as hint
6619 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6620 $format = qemu_img_format
($scfg, $src_volname);
6626 # test if requested format is supported - else use default
6627 my $supported = grep { $_ eq $format } @$validFormats;
6628 $format = $defFormat if !$supported;
6632 sub resolve_first_disk
{
6634 my @disks = PVE
::QemuServer
::valid_drive_names
();
6636 foreach my $ds (reverse @disks) {
6637 next if !$conf->{$ds};
6638 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6639 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6645 sub generate_smbios1_uuid
{
6646 my ($uuid, $uuid_str);
6647 UUID
::generate
($uuid);
6648 UUID
::unparse
($uuid, $uuid_str);
6649 return "uuid=$uuid_str";
6652 # bash completion helper
6654 sub complete_backup_archives
{
6655 my ($cmdname, $pname, $cvalue) = @_;
6657 my $cfg = PVE
::Storage
::config
();
6661 if ($cvalue =~ m/^([^:]+):/) {
6665 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6668 foreach my $id (keys %$data) {
6669 foreach my $item (@{$data->{$id}}) {
6670 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6671 push @$res, $item->{volid
} if defined($item->{volid
});
6678 my $complete_vmid_full = sub {
6681 my $idlist = vmstatus
();
6685 foreach my $id (keys %$idlist) {
6686 my $d = $idlist->{$id};
6687 if (defined($running)) {
6688 next if $d->{template
};
6689 next if $running && $d->{status
} ne 'running';
6690 next if !$running && $d->{status
} eq 'running';
6699 return &$complete_vmid_full();
6702 sub complete_vmid_stopped
{
6703 return &$complete_vmid_full(0);
6706 sub complete_vmid_running
{
6707 return &$complete_vmid_full(1);
6710 sub complete_storage
{
6712 my $cfg = PVE
::Storage
::config
();
6713 my $ids = $cfg->{ids
};
6716 foreach my $sid (keys %$ids) {
6717 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6718 next if !$ids->{$sid}->{content
}->{images
};
6728 vm_mon_cmd
($vmid, 'nbd-server-stop');