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 $OVMF_CODE = '/usr/share/kvm/OVMF_CODE-pure-efi.fd';
42 my $OVMF_VARS = '/usr/share/kvm/OVMF_VARS-pure-efi.fd';
44 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
46 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
48 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
50 # Note about locking: we use flock on the config file protect
51 # against concurent actions.
52 # Aditionaly, we have a 'lock' setting in the config file. This
53 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
54 # allowed when such lock is set. But you can ignore this kind of
55 # lock with the --skiplock flag.
57 cfs_register_file
('/qemu-server/',
61 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
62 description
=> "Some command save/restore state from this location.",
68 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
69 description
=> "The name of the snapshot.",
70 type
=> 'string', format
=> 'pve-configid',
74 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
76 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
77 description
=> "The drive's backing file's data format.",
81 #no warnings 'redefine';
84 my ($controller, $vmid, $option, $value) = @_;
86 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
87 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
91 my $nodename = PVE
::INotify
::nodename
();
93 mkdir "/etc/pve/nodes/$nodename";
94 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
97 my $var_run_tmpdir = "/var/run/qemu-server";
98 mkdir $var_run_tmpdir;
100 my $lock_dir = "/var/lock/qemu-server";
103 my $pcisysfs = "/sys/bus/pci";
105 my $cpu_vendor_list = {
107 486 => 'GenuineIntel',
108 pentium
=> 'GenuineIntel',
109 pentium2
=> 'GenuineIntel',
110 pentium3
=> 'GenuineIntel',
111 coreduo
=> 'GenuineIntel',
112 core2duo
=> 'GenuineIntel',
113 Conroe
=> 'GenuineIntel',
114 Penryn
=> 'GenuineIntel',
115 Nehalem
=> 'GenuineIntel',
116 'Nehalem-IBRS' => 'GenuineIntel',
117 Westmere
=> 'GenuineIntel',
118 'Westmere-IBRS' => 'GenuineIntel',
119 SandyBridge
=> 'GenuineIntel',
120 'SandyBridge-IBRS' => 'GenuineIntel',
121 IvyBridge
=> 'GenuineIntel',
122 'IvyBridge-IBRS' => 'GenuineIntel',
123 Haswell
=> 'GenuineIntel',
124 'Haswell-IBRS' => 'GenuineIntel',
125 'Haswell-noTSX' => 'GenuineIntel',
126 'Haswell-noTSX-IBRS' => 'GenuineIntel',
127 Broadwell
=> 'GenuineIntel',
128 'Broadwell-IBRS' => 'GenuineIntel',
129 'Broadwell-noTSX' => 'GenuineIntel',
130 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
131 'Skylake-Client' => 'GenuineIntel',
132 'Skylake-Client-IBRS' => 'GenuineIntel',
133 'Skylake-Server' => 'GenuineIntel',
134 'Skylake-Server-IBRS' => 'GenuineIntel',
137 athlon
=> 'AuthenticAMD',
138 phenom
=> 'AuthenticAMD',
139 Opteron_G1
=> 'AuthenticAMD',
140 Opteron_G2
=> 'AuthenticAMD',
141 Opteron_G3
=> 'AuthenticAMD',
142 Opteron_G4
=> 'AuthenticAMD',
143 Opteron_G5
=> 'AuthenticAMD',
144 EPYC
=> 'AuthenticAMD',
145 'EPYC-IBPB' => 'AuthenticAMD',
147 # generic types, use vendor from host node
156 my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
160 description
=> "Emulated CPU type.",
162 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
167 description
=> "Do not identify as a KVM virtual machine.",
173 description
=> "List of additional CPU flags separated by ';'."
174 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
175 . " Currently supported flags: 'pcid', 'spec-ctrl'.",
176 format_description
=> '+FLAG[;-FLAG...]',
178 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
187 enum
=> [qw(i6300esb ib700)],
188 description
=> "Watchdog type to emulate.",
189 default => 'i6300esb',
194 enum
=> [qw(reset shutdown poweroff pause debug none)],
195 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
199 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
205 description
=> "Specifies whether a VM will be started during system bootup.",
211 description
=> "Automatic restart after crash (currently ignored).",
216 type
=> 'string', format
=> 'pve-hotplug-features',
217 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'.",
218 default => 'network,disk,usb',
223 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
229 description
=> "Lock/unlock the VM.",
230 enum
=> [qw(migrate backup snapshot rollback)],
235 description
=> "Limit of CPU usage.",
236 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.",
244 description
=> "CPU weight for a VM.",
245 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.",
253 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
260 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
266 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",
274 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.".
275 "It should not be necessary to set it.",
276 enum
=> PVE
::Tools
::kvmkeymaplist
(),
281 type
=> 'string', format
=> 'dns-name',
282 description
=> "Set a name for the VM. Only used on the configuration web interface.",
287 description
=> "SCSI controller model",
288 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
294 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
299 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
300 description
=> "Specify guest operating system.",
301 verbose_description
=> <<EODESC,
302 Specify guest operating system. This is used to enable special
303 optimization/features for specific operating systems:
306 other;; unspecified OS
307 wxp;; Microsoft Windows XP
308 w2k;; Microsoft Windows 2000
309 w2k3;; Microsoft Windows 2003
310 w2k8;; Microsoft Windows 2008
311 wvista;; Microsoft Windows Vista
312 win7;; Microsoft Windows 7
313 win8;; Microsoft Windows 8/2012/2012r2
314 win10;; Microsoft Windows 10/2016
315 l24;; Linux 2.4 Kernel
316 l26;; Linux 2.6/3.X Kernel
317 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
323 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
324 pattern
=> '[acdn]{1,4}',
329 type
=> 'string', format
=> 'pve-qm-bootdisk',
330 description
=> "Enable booting from specified disk.",
331 pattern
=> '(ide|sata|scsi|virtio)\d+',
336 description
=> "The number of CPUs. Please use option -sockets instead.",
343 description
=> "The number of CPU sockets.",
350 description
=> "The number of cores per socket.",
357 description
=> "Enable/disable NUMA.",
363 description
=> "Enable/disable hugepages memory.",
364 enum
=> [qw(any 2 1024)],
369 description
=> "Number of hotplugged vcpus.",
376 description
=> "Enable/disable ACPI.",
382 description
=> "Enable/disable Qemu GuestAgent.",
388 description
=> "Enable/disable KVM hardware virtualization.",
394 description
=> "Enable/disable time drift fix.",
400 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
405 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
410 description
=> "Select the VGA type.",
411 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
412 " modes (>= 1280x1024x16) then you should use the options " .
413 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
414 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
415 "display sever. For win* OS you can select how many independent " .
416 "displays you want, Linux guests can add displays them self. " .
417 "You can also run without any graphic card, using a serial device" .
419 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
423 type
=> 'string', format
=> 'pve-qm-watchdog',
424 description
=> "Create a virtual hardware watchdog device.",
425 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
426 " (by a guest action), the watchdog must be periodically polled " .
427 "by an agent inside the guest or else the watchdog will reset " .
428 "the guest (or execute the respective action specified)",
433 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
434 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'.",
435 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
438 startup
=> get_standard_option
('pve-startup-order'),
442 description
=> "Enable/disable Template.",
448 description
=> "Arbitrary arguments passed to kvm.",
449 verbose_description
=> <<EODESCR,
450 Arbitrary arguments passed to kvm, for example:
452 args: -no-reboot -no-hpet
454 NOTE: this option is for experts only.
461 description
=> "Enable/disable the USB tablet device.",
462 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
463 "usually needed to allow absolute mouse positioning with VNC. " .
464 "Else the mouse runs out of sync with normal VNC clients. " .
465 "If you're running lots of console-only guests on one host, " .
466 "you may consider disabling this to save some context switches. " .
467 "This is turned off by default if you use spice (-vga=qxl).",
472 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
476 migrate_downtime
=> {
479 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
485 type
=> 'string', format
=> 'pve-qm-ide',
486 typetext
=> '<volume>',
487 description
=> "This is an alias for option -ide2",
491 description
=> "Emulated CPU type.",
495 parent
=> get_standard_option
('pve-snapshot-name', {
497 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
501 description
=> "Timestamp for snapshots.",
507 type
=> 'string', format
=> 'pve-volume-id',
508 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
510 vmstatestorage
=> get_standard_option
('pve-storage-id', {
511 description
=> "Default storage for VM state volumes/files.",
515 description
=> "Specific the Qemu machine type.",
517 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
522 description
=> "Specify SMBIOS type 1 fields.",
523 type
=> 'string', format
=> 'pve-qm-smbios1',
530 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
536 enum
=> [ qw(seabios ovmf) ],
537 description
=> "Select BIOS implementation.",
538 default => 'seabios',
543 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.",
547 type
=> 'string', format
=> 'address-list',
548 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.",
553 format
=> 'urlencoded',
554 description
=> "cloud-init : Setup public SSH keys (one key per line, " .
559 description
=> "cloud-init: Hostname to use instead of the vm-name + search-domain.",
560 type
=> 'string', format
=> 'dns-name',
565 # what about other qemu settings ?
567 #machine => 'string',
580 ##soundhw => 'string',
582 while (my ($k, $v) = each %$confdesc) {
583 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
586 my $MAX_IDE_DISKS = 4;
587 my $MAX_SCSI_DISKS = 14;
588 my $MAX_VIRTIO_DISKS = 16;
589 my $MAX_SATA_DISKS = 6;
590 my $MAX_USB_DEVICES = 5;
592 my $MAX_UNUSED_DISKS = 8;
593 my $MAX_HOSTPCI_DEVICES = 4;
594 my $MAX_SERIAL_PORTS = 4;
595 my $MAX_PARALLEL_PORTS = 3;
601 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
602 description
=> "CPUs accessing this NUMA node.",
603 format_description
=> "id[-id];...",
607 description
=> "Amount of memory this NUMA node provides.",
612 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
613 description
=> "Host NUMA nodes to use.",
614 format_description
=> "id[-id];...",
619 enum
=> [qw(preferred bind interleave)],
620 description
=> "NUMA allocation policy.",
624 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
627 type
=> 'string', format
=> $numa_fmt,
628 description
=> "NUMA topology.",
630 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
632 for (my $i = 0; $i < $MAX_NUMA; $i++) {
633 $confdesc->{"numa$i"} = $numadesc;
636 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
637 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
638 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
639 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
641 my $net_fmt_bridge_descr = <<__EOD__;
642 Bridge to attach the network device to. The Proxmox VE standard bridge
645 If you do not specify a bridge, we create a kvm user (NATed) network
646 device, which provides DHCP and DNS services. The following addresses
653 The DHCP server assign addresses to the guest starting from 10.0.2.15.
659 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
660 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
661 format_description
=> "XX:XX:XX:XX:XX:XX",
666 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'.",
667 enum
=> $nic_model_list,
670 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
673 description
=> $net_fmt_bridge_descr,
674 format_description
=> 'bridge',
679 minimum
=> 0, maximum
=> 16,
680 description
=> 'Number of packet queues to be used on the device.',
686 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
691 minimum
=> 1, maximum
=> 4094,
692 description
=> 'VLAN tag to apply to packets on this interface.',
697 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
698 description
=> 'VLAN trunks to pass through this interface.',
699 format_description
=> 'vlanid[;vlanid...]',
704 description
=> 'Whether this interface should be protected by the firewall.',
709 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
716 type
=> 'string', format
=> $net_fmt,
717 description
=> "Specify network devices.",
720 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
725 format
=> 'pve-ipv4-config',
726 format_description
=> 'IPv4Format/CIDR',
727 description
=> 'IPv4 address in CIDR format.',
734 format_description
=> 'GatewayIPv4',
735 description
=> 'Default gateway for IPv4 traffic.',
741 format
=> 'pve-ipv6-config',
742 format_description
=> 'IPv6Format/CIDR',
743 description
=> 'IPv6 address in CIDR format.',
750 format_description
=> 'GatewayIPv6',
751 description
=> 'Default gateway for IPv6 traffic.',
756 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
759 type
=> 'string', format
=> 'pve-qm-ipconfig',
760 description
=> <<'EODESCR',
761 cloud-init: Specify IP addresses and gateways for the corresponding interface.
763 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
765 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
766 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
768 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
771 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
773 for (my $i = 0; $i < $MAX_NETS; $i++) {
774 $confdesc->{"net$i"} = $netdesc;
775 $confdesc->{"ipconfig$i"} = $ipconfigdesc;
778 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
779 sub verify_volume_id_or_qm_path
{
780 my ($volid, $noerr) = @_;
782 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
786 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
787 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
789 return undef if $noerr;
797 my %drivedesc_base = (
798 volume
=> { alias
=> 'file' },
801 format
=> 'pve-volume-id-or-qm-path',
803 format_description
=> 'volume',
804 description
=> "The drive's backing volume.",
808 enum
=> [qw(cdrom disk)],
809 description
=> "The drive's media type.",
815 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
820 description
=> "Force the drive's physical geometry to have a specific head count.",
825 description
=> "Force the drive's physical geometry to have a specific sector count.",
830 enum
=> [qw(none lba auto)],
831 description
=> "Force disk geometry bios translation mode.",
836 description
=> "Controls qemu's snapshot mode feature."
837 . " If activated, changes made to the disk are temporary and will"
838 . " be discarded when the VM is shutdown.",
843 enum
=> [qw(none writethrough writeback unsafe directsync)],
844 description
=> "The drive's cache mode",
847 format
=> get_standard_option
('pve-qm-image-format'),
850 format
=> 'disk-size',
851 format_description
=> 'DiskSize',
852 description
=> "Disk size. This is purely informational and has no effect.",
857 description
=> "Whether the drive should be included when making backups.",
862 description
=> 'Whether the drive should considered for replication jobs.',
868 enum
=> [qw(ignore report stop)],
869 description
=> 'Read error action.',
874 enum
=> [qw(enospc ignore report stop)],
875 description
=> 'Write error action.',
880 enum
=> [qw(native threads)],
881 description
=> 'AIO type to use.',
886 enum
=> [qw(ignore on)],
887 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
892 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
897 format
=> 'urlencoded',
898 format_description
=> 'serial',
899 maxLength
=> 20*3, # *3 since it's %xx url enoded
900 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
905 description
=> 'Mark this locally-managed volume as available on all nodes',
906 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!",
912 my %iothread_fmt = ( iothread
=> {
914 description
=> "Whether to use iothreads for this drive",
921 format
=> 'urlencoded',
922 format_description
=> 'model',
923 maxLength
=> 40*3, # *3 since it's %xx url enoded
924 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
932 description
=> "Number of queues.",
938 my %scsiblock_fmt = (
941 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",
947 my $add_throttle_desc = sub {
948 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
951 format_description
=> $unit,
952 description
=> "Maximum $what in $longunit.",
955 $d->{minimum
} = $minimum if defined($minimum);
956 $drivedesc_base{$key} = $d;
958 # throughput: (leaky bucket)
959 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
960 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
961 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
962 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
963 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
964 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
965 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
966 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
967 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
969 # pools: (pool of IO before throttling starts taking effect)
970 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
971 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
972 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
973 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
974 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
975 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
978 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
979 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
980 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
981 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
982 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
983 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
986 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
987 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
988 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
989 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
995 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
999 type
=> 'string', format
=> $ide_fmt,
1000 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1002 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1012 type
=> 'string', format
=> $scsi_fmt,
1013 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1015 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1022 type
=> 'string', format
=> $sata_fmt,
1023 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1025 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1033 type
=> 'string', format
=> $virtio_fmt,
1034 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1036 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1038 my $alldrive_fmt = {
1047 volume
=> { alias
=> 'file' },
1050 format
=> 'pve-volume-id-or-qm-path',
1052 format_description
=> 'volume',
1053 description
=> "The drive's backing volume.",
1055 format
=> get_standard_option
('pve-qm-image-format'),
1058 format
=> 'disk-size',
1059 format_description
=> 'DiskSize',
1060 description
=> "Disk size. This is purely informational and has no effect.",
1065 my $efidisk_desc = {
1067 type
=> 'string', format
=> $efidisk_fmt,
1068 description
=> "Configure a Disk for storing EFI vars",
1071 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1076 type
=> 'string', format
=> 'pve-qm-usb-device',
1077 format_description
=> 'HOSTUSBDEVICE|spice',
1078 description
=> <<EODESCR,
1079 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1081 'bus-port(.port)*' (decimal numbers) or
1082 'vendor_id:product_id' (hexadeciaml numbers) or
1085 You can use the 'lsusb -t' command to list existing usb devices.
1087 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1089 The value 'spice' can be used to add a usb redirection devices for spice.
1095 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).",
1102 type
=> 'string', format
=> $usb_fmt,
1103 description
=> "Configure an USB device (n is 0 to 4).",
1105 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1107 # NOTE: the match-groups of this regex are used in parse_hostpci
1108 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1113 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1114 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1115 description
=> <<EODESCR,
1116 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1117 of PCI virtual functions of the host. HOSTPCIID syntax is:
1119 'bus:dev.func' (hexadecimal numbers)
1121 You can us the 'lspci' command to list existing PCI devices.
1126 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1132 pattern
=> '[^,;]+',
1133 format_description
=> 'string',
1134 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1139 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1145 description
=> "Enable vfio-vga device support.",
1150 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1154 type
=> 'string', format
=> 'pve-qm-hostpci',
1155 description
=> "Map host PCI devices into guest.",
1156 verbose_description
=> <<EODESCR,
1157 Map host PCI devices into guest.
1159 NOTE: This option allows direct access to host hardware. So it is no longer
1160 possible to migrate such machines - use with special care.
1162 CAUTION: Experimental! User reported problems with this option.
1165 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1170 pattern
=> '(/dev/.+|socket)',
1171 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1172 verbose_description
=> <<EODESCR,
1173 Create a serial device inside the VM (n is 0 to 3), and pass through a
1174 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1175 host side (use 'qm terminal' to open a terminal connection).
1177 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1179 CAUTION: Experimental! User reported problems with this option.
1186 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1187 description
=> "Map host parallel devices (n is 0 to 2).",
1188 verbose_description
=> <<EODESCR,
1189 Map host parallel devices (n is 0 to 2).
1191 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1193 CAUTION: Experimental! User reported problems with this option.
1197 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1198 $confdesc->{"parallel$i"} = $paralleldesc;
1201 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1202 $confdesc->{"serial$i"} = $serialdesc;
1205 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1206 $confdesc->{"hostpci$i"} = $hostpcidesc;
1209 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1210 $drivename_hash->{"ide$i"} = 1;
1211 $confdesc->{"ide$i"} = $idedesc;
1214 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1215 $drivename_hash->{"sata$i"} = 1;
1216 $confdesc->{"sata$i"} = $satadesc;
1219 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1220 $drivename_hash->{"scsi$i"} = 1;
1221 $confdesc->{"scsi$i"} = $scsidesc ;
1224 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1225 $drivename_hash->{"virtio$i"} = 1;
1226 $confdesc->{"virtio$i"} = $virtiodesc;
1229 $drivename_hash->{efidisk0
} = 1;
1230 $confdesc->{efidisk0
} = $efidisk_desc;
1232 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1233 $confdesc->{"usb$i"} = $usbdesc;
1238 type
=> 'string', format
=> 'pve-volume-id',
1239 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1242 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1243 $confdesc->{"unused$i"} = $unuseddesc;
1246 my $kvm_api_version = 0;
1250 return $kvm_api_version if $kvm_api_version;
1252 my $fh = IO
::File-
>new("</dev/kvm") ||
1255 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1256 $kvm_api_version = $v;
1261 return $kvm_api_version;
1264 my $kvm_user_version;
1266 sub kvm_user_version
{
1268 return $kvm_user_version if $kvm_user_version;
1270 $kvm_user_version = 'unknown';
1274 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1275 $kvm_user_version = $2;
1279 eval { run_command
("kvm -version", outfunc
=> $code); };
1282 return $kvm_user_version;
1286 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1288 sub valid_drive_names
{
1289 # order is important - used to autoselect boot disk
1290 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1291 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1292 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1293 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1297 sub is_valid_drivename
{
1300 return defined($drivename_hash->{$dev});
1305 return defined($confdesc->{$key});
1309 return $nic_model_list;
1312 sub os_list_description
{
1316 wxp
=> 'Windows XP',
1317 w2k
=> 'Windows 2000',
1318 w2k3
=>, 'Windows 2003',
1319 w2k8
=> 'Windows 2008',
1320 wvista
=> 'Windows Vista',
1321 win7
=> 'Windows 7',
1322 win8
=> 'Windows 8/2012',
1323 win10
=> 'Windows 10/2016',
1331 sub get_cdrom_path
{
1333 return $cdrom_path if $cdrom_path;
1335 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1336 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1337 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1341 my ($storecfg, $vmid, $cdrom) = @_;
1343 if ($cdrom eq 'cdrom') {
1344 return get_cdrom_path
();
1345 } elsif ($cdrom eq 'none') {
1347 } elsif ($cdrom =~ m
|^/|) {
1350 return PVE
::Storage
::path
($storecfg, $cdrom);
1354 # try to convert old style file names to volume IDs
1355 sub filename_to_volume_id
{
1356 my ($vmid, $file, $media) = @_;
1358 if (!($file eq 'none' || $file eq 'cdrom' ||
1359 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1361 return undef if $file =~ m
|/|;
1363 if ($media && $media eq 'cdrom') {
1364 $file = "local:iso/$file";
1366 $file = "local:$vmid/$file";
1373 sub verify_media_type
{
1374 my ($opt, $vtype, $media) = @_;
1379 if ($media eq 'disk') {
1381 } elsif ($media eq 'cdrom') {
1384 die "internal error";
1387 return if ($vtype eq $etype);
1389 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1392 sub cleanup_drive_path
{
1393 my ($opt, $storecfg, $drive) = @_;
1395 # try to convert filesystem paths to volume IDs
1397 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1398 ($drive->{file
} !~ m
|^/dev/.+|) &&
1399 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1400 ($drive->{file
} !~ m/^\d+$/)) {
1401 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1402 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1403 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1404 verify_media_type
($opt, $vtype, $drive->{media
});
1405 $drive->{file
} = $volid;
1408 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1411 sub parse_hotplug_features
{
1416 return $res if $data eq '0';
1418 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1420 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1421 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1424 die "invalid hotplug feature '$feature'\n";
1430 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1431 sub pve_verify_hotplug_features
{
1432 my ($value, $noerr) = @_;
1434 return $value if parse_hotplug_features
($value);
1436 return undef if $noerr;
1438 die "unable to parse hotplug option\n";
1441 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1442 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1443 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1444 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1445 # [,iothread=on][,serial=serial][,model=model]
1448 my ($key, $data) = @_;
1450 my ($interface, $index);
1452 if ($key =~ m/^([^\d]+)(\d+)$/) {
1459 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1460 : $confdesc->{$key}->{format
};
1462 warn "invalid drive key: $key\n";
1465 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1466 return undef if !$res;
1467 $res->{interface
} = $interface;
1468 $res->{index} = $index;
1471 foreach my $opt (qw(bps bps_rd bps_wr)) {
1472 if (my $bps = defined(delete $res->{$opt})) {
1473 if (defined($res->{"m$opt"})) {
1474 warn "both $opt and m$opt specified\n";
1478 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1482 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1483 for my $requirement (
1484 [mbps_max
=> 'mbps'],
1485 [mbps_rd_max
=> 'mbps_rd'],
1486 [mbps_wr_max
=> 'mbps_wr'],
1487 [miops_max
=> 'miops'],
1488 [miops_rd_max
=> 'miops_rd'],
1489 [miops_wr_max
=> 'miops_wr'],
1490 [bps_max_length
=> 'mbps_max'],
1491 [bps_rd_max_length
=> 'mbps_rd_max'],
1492 [bps_wr_max_length
=> 'mbps_wr_max'],
1493 [iops_max_length
=> 'iops_max'],
1494 [iops_rd_max_length
=> 'iops_rd_max'],
1495 [iops_wr_max_length
=> 'iops_wr_max']) {
1496 my ($option, $requires) = @$requirement;
1497 if ($res->{$option} && !$res->{$requires}) {
1498 warn "$option requires $requires\n";
1503 return undef if $error;
1505 return undef if $res->{mbps_rd
} && $res->{mbps
};
1506 return undef if $res->{mbps_wr
} && $res->{mbps
};
1507 return undef if $res->{iops_rd
} && $res->{iops
};
1508 return undef if $res->{iops_wr
} && $res->{iops
};
1510 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1511 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1512 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1513 return undef if $res->{interface
} eq 'virtio';
1516 if (my $size = $res->{size
}) {
1517 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1524 my ($vmid, $drive) = @_;
1525 my $data = { %$drive };
1526 delete $data->{$_} for qw(index interface);
1527 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1531 my($fh, $noerr) = @_;
1534 my $SG_GET_VERSION_NUM = 0x2282;
1536 my $versionbuf = "\x00" x
8;
1537 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1539 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1542 my $version = unpack("I", $versionbuf);
1543 if ($version < 30000) {
1544 die "scsi generic interface too old\n" if !$noerr;
1548 my $buf = "\x00" x
36;
1549 my $sensebuf = "\x00" x
8;
1550 my $cmd = pack("C x3 C x1", 0x12, 36);
1552 # see /usr/include/scsi/sg.h
1553 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";
1555 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1556 length($sensebuf), 0, length($buf), $buf,
1557 $cmd, $sensebuf, 6000);
1559 $ret = ioctl($fh, $SG_IO, $packet);
1561 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1565 my @res = unpack($sg_io_hdr_t, $packet);
1566 if ($res[17] || $res[18]) {
1567 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1572 (my $byte0, my $byte1, $res->{vendor
},
1573 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1575 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1576 $res->{type
} = $byte0 & 31;
1584 my $fh = IO
::File-
>new("+<$path") || return undef;
1585 my $res = scsi_inquiry
($fh, 1);
1591 sub machine_type_is_q35
{
1594 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1597 sub print_tabletdevice_full
{
1600 my $q35 = machine_type_is_q35
($conf);
1602 # we use uhci for old VMs because tablet driver was buggy in older qemu
1603 my $usbbus = $q35 ?
"ehci" : "uhci";
1605 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1608 sub print_drivedevice_full
{
1609 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1614 if ($drive->{interface
} eq 'virtio') {
1615 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1616 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1617 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1618 } elsif ($drive->{interface
} eq 'scsi') {
1620 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1621 my $unit = $drive->{index} % $maxdev;
1622 my $devicetype = 'hd';
1624 if (drive_is_cdrom
($drive)) {
1627 if ($drive->{file
} =~ m
|^/|) {
1628 $path = $drive->{file
};
1629 if (my $info = path_is_scsi
($path)) {
1630 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1631 $devicetype = 'block';
1632 } elsif ($info->{type
} == 1) { # tape
1633 $devicetype = 'generic';
1637 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1640 if($path =~ m/^iscsi\:\/\
//){
1641 $devicetype = 'generic';
1645 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1646 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1648 $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}";
1651 } elsif ($drive->{interface
} eq 'ide'){
1653 my $controller = int($drive->{index} / $maxdev);
1654 my $unit = $drive->{index} % $maxdev;
1655 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1657 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1658 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1659 $model = URI
::Escape
::uri_unescape
($model);
1660 $device .= ",model=$model";
1662 } elsif ($drive->{interface
} eq 'sata'){
1663 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1664 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1665 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1666 } elsif ($drive->{interface
} eq 'usb') {
1668 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1670 die "unsupported interface type";
1673 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1678 sub get_initiator_name
{
1681 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1682 while (defined(my $line = <$fh>)) {
1683 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1692 sub print_drive_full
{
1693 my ($storecfg, $vmid, $drive) = @_;
1696 my $volid = $drive->{file
};
1699 if (drive_is_cdrom
($drive)) {
1700 $path = get_iso_path
($storecfg, $vmid, $volid);
1702 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1704 $path = PVE
::Storage
::path
($storecfg, $volid);
1705 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1706 $format = qemu_img_format
($scfg, $volname);
1714 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1715 foreach my $o (@qemu_drive_options) {
1716 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1719 # snapshot only accepts on|off
1720 if (defined($drive->{snapshot
})) {
1721 my $v = $drive->{snapshot
} ?
'on' : 'off';
1722 $opts .= ",snapshot=$v";
1725 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1726 my ($dir, $qmpname) = @$type;
1727 if (my $v = $drive->{"mbps$dir"}) {
1728 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1730 if (my $v = $drive->{"mbps${dir}_max"}) {
1731 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1733 if (my $v = $drive->{"bps${dir}_max_length"}) {
1734 $opts .= ",throttling.bps$qmpname-max-length=$v";
1736 if (my $v = $drive->{"iops${dir}"}) {
1737 $opts .= ",throttling.iops$qmpname=$v";
1739 if (my $v = $drive->{"iops${dir}_max"}) {
1740 $opts .= ",throttling.iops$qmpname-max=$v";
1742 if (my $v = $drive->{"iops${dir}_max_length"}) {
1743 $opts .= ",throttling.iops$qmpname-max-length=$v";
1747 if (my $serial = $drive->{serial
}) {
1748 $serial = URI
::Escape
::uri_unescape
($serial);
1749 $opts .= ",serial=$serial";
1752 $opts .= ",format=$format" if $format && !$drive->{format
};
1754 my $cache_direct = 0;
1756 if (my $cache = $drive->{cache
}) {
1757 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1758 } elsif (!drive_is_cdrom
($drive)) {
1759 $opts .= ",cache=none";
1763 # aio native works only with O_DIRECT
1764 if (!$drive->{aio
}) {
1766 $opts .= ",aio=native";
1768 $opts .= ",aio=threads";
1772 if (!drive_is_cdrom
($drive)) {
1774 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1775 $detectzeroes = 'off';
1776 } elsif ($drive->{discard
}) {
1777 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1779 # This used to be our default with discard not being specified:
1780 $detectzeroes = 'on';
1782 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1785 my $pathinfo = $path ?
"file=$path," : '';
1787 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1790 sub print_netdevice_full
{
1791 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1793 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1795 my $device = $net->{model
};
1796 if ($net->{model
} eq 'virtio') {
1797 $device = 'virtio-net-pci';
1800 my $pciaddr = print_pci_addr
("$netid", $bridges);
1801 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1802 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1803 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1804 my $vectors = $net->{queues
} * 2 + 2;
1805 $tmpstr .= ",vectors=$vectors,mq=on";
1807 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1809 if ($use_old_bios_files) {
1811 if ($device eq 'virtio-net-pci') {
1812 $romfile = 'pxe-virtio.rom';
1813 } elsif ($device eq 'e1000') {
1814 $romfile = 'pxe-e1000.rom';
1815 } elsif ($device eq 'ne2k') {
1816 $romfile = 'pxe-ne2k_pci.rom';
1817 } elsif ($device eq 'pcnet') {
1818 $romfile = 'pxe-pcnet.rom';
1819 } elsif ($device eq 'rtl8139') {
1820 $romfile = 'pxe-rtl8139.rom';
1822 $tmpstr .= ",romfile=$romfile" if $romfile;
1828 sub print_netdev_full
{
1829 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1832 if ($netid =~ m/^net(\d+)$/) {
1836 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1838 my $ifname = "tap${vmid}i$i";
1840 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1841 die "interface name '$ifname' is too long (max 15 character)\n"
1842 if length($ifname) >= 16;
1844 my $vhostparam = '';
1845 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1847 my $vmname = $conf->{name
} || "vm$vmid";
1850 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1852 if ($net->{bridge
}) {
1853 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1855 $netdev = "type=user,id=$netid,hostname=$vmname";
1858 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1864 sub print_cpu_device
{
1865 my ($conf, $id) = @_;
1867 my $kvm = $conf->{kvm
} // 1;
1868 my $cpu = $kvm ?
"kvm64" : "qemu64";
1869 if (my $cputype = $conf->{cpu
}) {
1870 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1871 or die "Cannot parse cpu description: $cputype\n";
1872 $cpu = $cpuconf->{cputype
};
1875 my $cores = $conf->{cores
} || 1;
1877 my $current_core = ($id - 1) % $cores;
1878 my $current_socket = int(($id - 1 - $current_core)/$cores);
1880 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1883 sub drive_is_cdrom
{
1884 my ($drive, $exclude_cloudinit) = @_;
1886 return 0 if $exclude_cloudinit && $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1888 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1892 sub parse_number_sets
{
1895 foreach my $part (split(/;/, $set)) {
1896 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1897 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1898 push @$res, [ $1, $2 ];
1900 die "invalid range: $part\n";
1909 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1910 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1911 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1918 return undef if !$value;
1920 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1922 my @idlist = split(/;/, $res->{host
});
1923 delete $res->{host
};
1924 foreach my $id (@idlist) {
1925 if ($id =~ /^$PCIRE$/) {
1927 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1929 my $pcidevices = lspci
($1);
1930 $res->{pciid
} = $pcidevices->{$1};
1933 # should have been caught by parse_property_string already
1934 die "failed to parse PCI id: $id\n";
1940 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1944 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1949 if (!defined($res->{macaddr
})) {
1950 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1951 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1953 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
() if !defined($res->{macaddr
});
1957 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1958 sub parse_ipconfig
{
1961 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1967 if ($res->{gw
} && !$res->{ip
}) {
1968 warn 'gateway specified without specifying an IP address';
1971 if ($res->{gw6
} && !$res->{ip6
}) {
1972 warn 'IPv6 gateway specified without specifying an IPv6 address';
1975 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1976 warn 'gateway specified together with DHCP';
1979 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1981 warn "IPv6 gateway specified together with $res->{ip6} address";
1985 if (!$res->{ip
} && !$res->{ip6
}) {
1986 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1995 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1998 sub add_random_macs
{
1999 my ($settings) = @_;
2001 foreach my $opt (keys %$settings) {
2002 next if $opt !~ m/^net(\d+)$/;
2003 my $net = parse_net
($settings->{$opt});
2005 $settings->{$opt} = print_net
($net);
2009 sub vm_is_volid_owner
{
2010 my ($storecfg, $vmid, $volid) = @_;
2012 if ($volid !~ m
|^/|) {
2014 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2015 if ($owner && ($owner == $vmid)) {
2023 sub split_flagged_list
{
2024 my $text = shift || '';
2025 $text =~ s/[,;]/ /g;
2027 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2030 sub join_flagged_list
{
2031 my ($how, $lst) = @_;
2032 join $how, map { $lst->{$_} . $_ } keys %$lst;
2035 sub vmconfig_delete_pending_option
{
2036 my ($conf, $key, $force) = @_;
2038 delete $conf->{pending
}->{$key};
2039 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2040 $pending_delete_hash->{$key} = $force ?
'!' : '';
2041 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2044 sub vmconfig_undelete_pending_option
{
2045 my ($conf, $key) = @_;
2047 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2048 delete $pending_delete_hash->{$key};
2050 if (%$pending_delete_hash) {
2051 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2053 delete $conf->{pending
}->{delete};
2057 sub vmconfig_register_unused_drive
{
2058 my ($storecfg, $vmid, $conf, $drive) = @_;
2060 if (!drive_is_cdrom
($drive, 1)) {
2061 my $volid = $drive->{file
};
2062 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2063 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2068 sub vmconfig_cleanup_pending
{
2071 # remove pending changes when nothing changed
2073 foreach my $opt (keys %{$conf->{pending
}}) {
2074 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2076 delete $conf->{pending
}->{$opt};
2080 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2081 my $pending_delete_hash = {};
2082 while (my ($opt, $force) = each %$current_delete_hash) {
2083 if (defined($conf->{$opt})) {
2084 $pending_delete_hash->{$opt} = $force;
2090 if (%$pending_delete_hash) {
2091 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2093 delete $conf->{pending
}->{delete};
2099 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2103 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2104 format_description
=> 'UUID',
2105 description
=> "Set SMBIOS1 UUID.",
2111 format_description
=> 'string',
2112 description
=> "Set SMBIOS1 version.",
2118 format_description
=> 'string',
2119 description
=> "Set SMBIOS1 serial number.",
2125 format_description
=> 'string',
2126 description
=> "Set SMBIOS1 manufacturer.",
2132 format_description
=> 'string',
2133 description
=> "Set SMBIOS1 product ID.",
2139 format_description
=> 'string',
2140 description
=> "Set SMBIOS1 SKU string.",
2146 format_description
=> 'string',
2147 description
=> "Set SMBIOS1 family string.",
2155 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2162 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2165 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2167 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2168 sub verify_bootdisk
{
2169 my ($value, $noerr) = @_;
2171 return $value if is_valid_drivename
($value);
2173 return undef if $noerr;
2175 die "invalid boot disk '$value'\n";
2178 sub parse_watchdog
{
2181 return undef if !$value;
2183 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2188 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2189 sub verify_usb_device
{
2190 my ($value, $noerr) = @_;
2192 return $value if parse_usb_device
($value);
2194 return undef if $noerr;
2196 die "unable to parse usb device\n";
2199 # add JSON properties for create and set function
2200 sub json_config_properties
{
2203 foreach my $opt (keys %$confdesc) {
2204 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2205 $prop->{$opt} = $confdesc->{$opt};
2212 my ($key, $value) = @_;
2214 die "unknown setting '$key'\n" if !$confdesc->{$key};
2216 my $type = $confdesc->{$key}->{type
};
2218 if (!defined($value)) {
2219 die "got undefined value\n";
2222 if ($value =~ m/[\n\r]/) {
2223 die "property contains a line feed\n";
2226 if ($type eq 'boolean') {
2227 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2228 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2229 die "type check ('boolean') failed - got '$value'\n";
2230 } elsif ($type eq 'integer') {
2231 return int($1) if $value =~ m/^(\d+)$/;
2232 die "type check ('integer') failed - got '$value'\n";
2233 } elsif ($type eq 'number') {
2234 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2235 die "type check ('number') failed - got '$value'\n";
2236 } elsif ($type eq 'string') {
2237 if (my $fmt = $confdesc->{$key}->{format
}) {
2238 PVE
::JSONSchema
::check_format
($fmt, $value);
2241 $value =~ s/^\"(.*)\"$/$1/;
2244 die "internal error"
2248 sub check_iommu_support
{
2249 #fixme : need to check IOMMU support
2250 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2260 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2261 utime undef, undef, $conf;
2265 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2267 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2269 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2271 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2273 if ($conf->{template
}) {
2274 # check if any base image is still used by a linked clone
2275 foreach_drive
($conf, sub {
2276 my ($ds, $drive) = @_;
2278 return if drive_is_cdrom
($drive);
2280 my $volid = $drive->{file
};
2282 return if !$volid || $volid =~ m
|^/|;
2284 die "base volume '$volid' is still in use by linked cloned\n"
2285 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2290 # only remove disks owned by this VM
2291 foreach_drive
($conf, sub {
2292 my ($ds, $drive) = @_;
2294 return if drive_is_cdrom
($drive, 1);
2296 my $volid = $drive->{file
};
2298 return if !$volid || $volid =~ m
|^/|;
2300 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2301 return if !$path || !$owner || ($owner != $vmid);
2304 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2306 warn "Could not remove disk '$volid', check manually: $@" if $@;
2310 if ($keep_empty_config) {
2311 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2316 # also remove unused disk
2318 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2321 PVE
::Storage
::foreach_volid
($dl, sub {
2322 my ($volid, $sid, $volname, $d) = @_;
2323 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2332 sub parse_vm_config
{
2333 my ($filename, $raw) = @_;
2335 return undef if !defined($raw);
2338 digest
=> Digest
::SHA
::sha1_hex
($raw),
2343 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2344 || die "got strange filename '$filename'";
2352 my @lines = split(/\n/, $raw);
2353 foreach my $line (@lines) {
2354 next if $line =~ m/^\s*$/;
2356 if ($line =~ m/^\[PENDING\]\s*$/i) {
2357 $section = 'pending';
2358 if (defined($descr)) {
2360 $conf->{description
} = $descr;
2363 $conf = $res->{$section} = {};
2366 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2368 if (defined($descr)) {
2370 $conf->{description
} = $descr;
2373 $conf = $res->{snapshots
}->{$section} = {};
2377 if ($line =~ m/^\#(.*)\s*$/) {
2378 $descr = '' if !defined($descr);
2379 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2383 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2384 $descr = '' if !defined($descr);
2385 $descr .= PVE
::Tools
::decode_text
($2);
2386 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2387 $conf->{snapstate
} = $1;
2388 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2391 $conf->{$key} = $value;
2392 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2394 if ($section eq 'pending') {
2395 $conf->{delete} = $value; # we parse this later
2397 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2399 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2402 eval { $value = check_type
($key, $value); };
2404 warn "vm $vmid - unable to parse value of '$key' - $@";
2406 $key = 'ide2' if $key eq 'cdrom';
2407 my $fmt = $confdesc->{$key}->{format
};
2408 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2409 my $v = parse_drive
($key, $value);
2410 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2411 $v->{file
} = $volid;
2412 $value = print_drive
($vmid, $v);
2414 warn "vm $vmid - unable to parse value of '$key'\n";
2419 $conf->{$key} = $value;
2424 if (defined($descr)) {
2426 $conf->{description
} = $descr;
2428 delete $res->{snapstate
}; # just to be sure
2433 sub write_vm_config
{
2434 my ($filename, $conf) = @_;
2436 delete $conf->{snapstate
}; # just to be sure
2438 if ($conf->{cdrom
}) {
2439 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2440 $conf->{ide2
} = $conf->{cdrom
};
2441 delete $conf->{cdrom
};
2444 # we do not use 'smp' any longer
2445 if ($conf->{sockets
}) {
2446 delete $conf->{smp
};
2447 } elsif ($conf->{smp
}) {
2448 $conf->{sockets
} = $conf->{smp
};
2449 delete $conf->{cores
};
2450 delete $conf->{smp
};
2453 my $used_volids = {};
2455 my $cleanup_config = sub {
2456 my ($cref, $pending, $snapname) = @_;
2458 foreach my $key (keys %$cref) {
2459 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2460 $key eq 'snapstate' || $key eq 'pending';
2461 my $value = $cref->{$key};
2462 if ($key eq 'delete') {
2463 die "propertry 'delete' is only allowed in [PENDING]\n"
2465 # fixme: check syntax?
2468 eval { $value = check_type
($key, $value); };
2469 die "unable to parse value of '$key' - $@" if $@;
2471 $cref->{$key} = $value;
2473 if (!$snapname && is_valid_drivename
($key)) {
2474 my $drive = parse_drive
($key, $value);
2475 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2480 &$cleanup_config($conf);
2482 &$cleanup_config($conf->{pending
}, 1);
2484 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2485 die "internal error" if $snapname eq 'pending';
2486 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2489 # remove 'unusedX' settings if we re-add a volume
2490 foreach my $key (keys %$conf) {
2491 my $value = $conf->{$key};
2492 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2493 delete $conf->{$key};
2497 my $generate_raw_config = sub {
2498 my ($conf, $pending) = @_;
2502 # add description as comment to top of file
2503 if (defined(my $descr = $conf->{description
})) {
2505 foreach my $cl (split(/\n/, $descr)) {
2506 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2509 $raw .= "#\n" if $pending;
2513 foreach my $key (sort keys %$conf) {
2514 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2515 $raw .= "$key: $conf->{$key}\n";
2520 my $raw = &$generate_raw_config($conf);
2522 if (scalar(keys %{$conf->{pending
}})){
2523 $raw .= "\n[PENDING]\n";
2524 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2527 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2528 $raw .= "\n[$snapname]\n";
2529 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2539 # we use static defaults from our JSON schema configuration
2540 foreach my $key (keys %$confdesc) {
2541 if (defined(my $default = $confdesc->{$key}->{default})) {
2542 $res->{$key} = $default;
2546 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2547 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2553 my $vmlist = PVE
::Cluster
::get_vmlist
();
2555 return $res if !$vmlist || !$vmlist->{ids
};
2556 my $ids = $vmlist->{ids
};
2558 foreach my $vmid (keys %$ids) {
2559 my $d = $ids->{$vmid};
2560 next if !$d->{node
} || $d->{node
} ne $nodename;
2561 next if !$d->{type
} || $d->{type
} ne 'qemu';
2562 $res->{$vmid}->{exists} = 1;
2567 # test if VM uses local resources (to prevent migration)
2568 sub check_local_resources
{
2569 my ($conf, $noerr) = @_;
2573 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2574 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2576 foreach my $k (keys %$conf) {
2577 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2578 # sockets are safe: they will recreated be on the target side post-migrate
2579 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2580 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2583 die "VM uses local resources\n" if $loc_res && !$noerr;
2588 # check if used storages are available on all nodes (use by migrate)
2589 sub check_storage_availability
{
2590 my ($storecfg, $conf, $node) = @_;
2592 foreach_drive
($conf, sub {
2593 my ($ds, $drive) = @_;
2595 my $volid = $drive->{file
};
2598 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2601 # check if storage is available on both nodes
2602 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2603 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2607 # list nodes where all VM images are available (used by has_feature API)
2609 my ($conf, $storecfg) = @_;
2611 my $nodelist = PVE
::Cluster
::get_nodelist
();
2612 my $nodehash = { map { $_ => 1 } @$nodelist };
2613 my $nodename = PVE
::INotify
::nodename
();
2615 foreach_drive
($conf, sub {
2616 my ($ds, $drive) = @_;
2618 my $volid = $drive->{file
};
2621 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2623 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2624 if ($scfg->{disable
}) {
2626 } elsif (my $avail = $scfg->{nodes
}) {
2627 foreach my $node (keys %$nodehash) {
2628 delete $nodehash->{$node} if !$avail->{$node};
2630 } elsif (!$scfg->{shared
}) {
2631 foreach my $node (keys %$nodehash) {
2632 delete $nodehash->{$node} if $node ne $nodename
2642 my ($pidfile, $pid) = @_;
2644 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2648 return undef if !$line;
2649 my @param = split(/\0/, $line);
2651 my $cmd = $param[0];
2652 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2654 for (my $i = 0; $i < scalar (@param); $i++) {
2657 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2658 my $p = $param[$i+1];
2659 return 1 if $p && ($p eq $pidfile);
2668 my ($vmid, $nocheck, $node) = @_;
2670 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2672 die "unable to find configuration file for VM $vmid - no such machine\n"
2673 if !$nocheck && ! -f
$filename;
2675 my $pidfile = pidfile_name
($vmid);
2677 if (my $fd = IO
::File-
>new("<$pidfile")) {
2682 my $mtime = $st->mtime;
2683 if ($mtime > time()) {
2684 warn "file '$filename' modified in future\n";
2687 if ($line =~ m/^(\d+)$/) {
2689 if (check_cmdline
($pidfile, $pid)) {
2690 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2702 my $vzlist = config_list
();
2704 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2706 while (defined(my $de = $fd->read)) {
2707 next if $de !~ m/^(\d+)\.pid$/;
2709 next if !defined($vzlist->{$vmid});
2710 if (my $pid = check_running
($vmid)) {
2711 $vzlist->{$vmid}->{pid
} = $pid;
2719 my ($storecfg, $conf) = @_;
2721 my $bootdisk = $conf->{bootdisk
};
2722 return undef if !$bootdisk;
2723 return undef if !is_valid_drivename
($bootdisk);
2725 return undef if !$conf->{$bootdisk};
2727 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2728 return undef if !defined($drive);
2730 return undef if drive_is_cdrom
($drive);
2732 my $volid = $drive->{file
};
2733 return undef if !$volid;
2735 return $drive->{size
};
2738 my $last_proc_pid_stat;
2740 # get VM status information
2741 # This must be fast and should not block ($full == false)
2742 # We only query KVM using QMP if $full == true (this can be slow)
2744 my ($opt_vmid, $full) = @_;
2748 my $storecfg = PVE
::Storage
::config
();
2750 my $list = vzlist
();
2751 my $defaults = load_defaults
();
2753 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2755 my $cpucount = $cpuinfo->{cpus
} || 1;
2757 foreach my $vmid (keys %$list) {
2758 next if $opt_vmid && ($vmid ne $opt_vmid);
2760 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2761 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2764 $d->{pid
} = $list->{$vmid}->{pid
};
2766 # fixme: better status?
2767 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2769 my $size = disksize
($storecfg, $conf);
2770 if (defined($size)) {
2771 $d->{disk
} = 0; # no info available
2772 $d->{maxdisk
} = $size;
2778 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2779 * ($conf->{cores
} || $defaults->{cores
});
2780 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2781 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2783 $d->{name
} = $conf->{name
} || "VM $vmid";
2784 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2785 : $defaults->{memory
}*(1024*1024);
2787 if ($conf->{balloon
}) {
2788 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2789 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2790 : $defaults->{shares
};
2801 $d->{diskwrite
} = 0;
2803 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2805 $d->{serial
} = 1 if conf_has_serial
($conf);
2810 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2811 foreach my $dev (keys %$netdev) {
2812 next if $dev !~ m/^tap([1-9]\d*)i/;
2814 my $d = $res->{$vmid};
2817 $d->{netout
} += $netdev->{$dev}->{receive
};
2818 $d->{netin
} += $netdev->{$dev}->{transmit
};
2821 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2822 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2827 my $ctime = gettimeofday
;
2829 foreach my $vmid (keys %$list) {
2831 my $d = $res->{$vmid};
2832 my $pid = $d->{pid
};
2835 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2836 next if !$pstat; # not running
2838 my $used = $pstat->{utime} + $pstat->{stime
};
2840 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2842 if ($pstat->{vsize
}) {
2843 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2846 my $old = $last_proc_pid_stat->{$pid};
2848 $last_proc_pid_stat->{$pid} = {
2856 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2858 if ($dtime > 1000) {
2859 my $dutime = $used - $old->{used
};
2861 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2862 $last_proc_pid_stat->{$pid} = {
2868 $d->{cpu
} = $old->{cpu
};
2872 return $res if !$full;
2874 my $qmpclient = PVE
::QMPClient-
>new();
2876 my $ballooncb = sub {
2877 my ($vmid, $resp) = @_;
2879 my $info = $resp->{'return'};
2880 return if !$info->{max_mem
};
2882 my $d = $res->{$vmid};
2884 # use memory assigned to VM
2885 $d->{maxmem
} = $info->{max_mem
};
2886 $d->{balloon
} = $info->{actual
};
2888 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2889 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2890 $d->{freemem
} = $info->{free_mem
};
2893 $d->{ballooninfo
} = $info;
2896 my $blockstatscb = sub {
2897 my ($vmid, $resp) = @_;
2898 my $data = $resp->{'return'} || [];
2899 my $totalrdbytes = 0;
2900 my $totalwrbytes = 0;
2902 for my $blockstat (@$data) {
2903 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2904 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2906 $blockstat->{device
} =~ s/drive-//;
2907 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2909 $res->{$vmid}->{diskread
} = $totalrdbytes;
2910 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2913 my $statuscb = sub {
2914 my ($vmid, $resp) = @_;
2916 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2917 # this fails if ballon driver is not loaded, so this must be
2918 # the last commnand (following command are aborted if this fails).
2919 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2921 my $status = 'unknown';
2922 if (!defined($status = $resp->{'return'}->{status
})) {
2923 warn "unable to get VM status\n";
2927 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2930 foreach my $vmid (keys %$list) {
2931 next if $opt_vmid && ($vmid ne $opt_vmid);
2932 next if !$res->{$vmid}->{pid
}; # not running
2933 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2936 $qmpclient->queue_execute(undef, 2);
2938 foreach my $vmid (keys %$list) {
2939 next if $opt_vmid && ($vmid ne $opt_vmid);
2940 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2947 my ($conf, $func, @param) = @_;
2949 foreach my $ds (valid_drive_names
()) {
2950 next if !defined($conf->{$ds});
2952 my $drive = parse_drive
($ds, $conf->{$ds});
2955 &$func($ds, $drive, @param);
2960 my ($conf, $func, @param) = @_;
2964 my $test_volid = sub {
2965 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
2969 $volhash->{$volid}->{cdrom
} //= 1;
2970 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
2972 $volhash->{$volid}->{replicate
} //= 0;
2973 $volhash->{$volid}->{replicate
} = 1 if $replicate;
2975 $volhash->{$volid}->{shared
} //= 0;
2976 $volhash->{$volid}->{shared
} = 1 if $shared;
2978 $volhash->{$volid}->{referenced_in_config
} //= 0;
2979 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
2981 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
2982 if defined($snapname);
2985 foreach_drive
($conf, sub {
2986 my ($ds, $drive) = @_;
2987 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
2990 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2991 my $snap = $conf->{snapshots
}->{$snapname};
2992 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
2993 foreach_drive
($snap, sub {
2994 my ($ds, $drive) = @_;
2995 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
2999 foreach my $volid (keys %$volhash) {
3000 &$func($volid, $volhash->{$volid}, @param);
3004 sub conf_has_serial
{
3007 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3008 if ($conf->{"serial$i"}) {
3016 sub vga_conf_has_spice
{
3019 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3024 sub config_to_command
{
3025 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3028 my $globalFlags = [];
3029 my $machineFlags = [];
3035 my $kvmver = kvm_user_version
();
3036 my $vernum = 0; # unknown
3037 my $ostype = $conf->{ostype
};
3038 my $winversion = windows_version
($ostype);
3039 my $kvm = $conf->{kvm
} // 1;
3041 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3043 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3044 $vernum = $1*1000000+$2*1000;
3045 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3046 $vernum = $1*1000000+$2*1000+$3;
3049 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3051 my $have_ovz = -f
'/proc/vz/vestat';
3053 my $q35 = machine_type_is_q35
($conf);
3054 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3055 my $machine_type = $forcemachine || $conf->{machine
};
3056 my $use_old_bios_files = undef;
3057 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3059 my $cpuunits = defined($conf->{cpuunits
}) ?
3060 $conf->{cpuunits
} : $defaults->{cpuunits
};
3062 push @$cmd, '/usr/bin/kvm';
3064 push @$cmd, '-id', $vmid;
3068 my $qmpsocket = qmp_socket
($vmid);
3069 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3070 push @$cmd, '-mon', "chardev=qmp,mode=control";
3073 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3075 push @$cmd, '-daemonize';
3077 if ($conf->{smbios1
}) {
3078 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3081 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3082 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3086 if (my $efidisk = $conf->{efidisk0
}) {
3087 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3088 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3089 $format = $d->{format
};
3091 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3092 if (!defined($format)) {
3093 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3094 $format = qemu_img_format
($scfg, $volname);
3098 die "efidisk format must be specified\n"
3099 if !defined($format);
3102 warn "no efidisk configured! Using temporary efivars disk.\n";
3103 $path = "/tmp/$vmid-ovmf.fd";
3104 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3108 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3109 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3113 # add usb controllers
3114 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3115 push @$devices, @usbcontrollers if @usbcontrollers;
3116 my $vga = $conf->{vga
};
3118 my $qxlnum = vga_conf_has_spice
($vga);
3119 $vga = 'qxl' if $qxlnum;
3122 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3123 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3125 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3129 # enable absolute mouse coordinates (needed by vnc)
3131 if (defined($conf->{tablet
})) {
3132 $tablet = $conf->{tablet
};
3134 $tablet = $defaults->{tablet
};
3135 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3136 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3139 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3142 my $gpu_passthrough;
3145 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3146 my $d = parse_hostpci
($conf->{"hostpci$i"});
3149 my $pcie = $d->{pcie
};
3151 die "q35 machine model is not enabled" if !$q35;
3152 $pciaddr = print_pcie_addr
("hostpci$i");
3154 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3157 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3158 my $romfile = $d->{romfile
};
3161 if ($d->{'x-vga'}) {
3162 $xvga = ',x-vga=on';
3165 $gpu_passthrough = 1;
3167 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3171 my $pcidevices = $d->{pciid
};
3172 my $multifunction = 1 if @$pcidevices > 1;
3175 foreach my $pcidevice (@$pcidevices) {
3177 my $id = "hostpci$i";
3178 $id .= ".$j" if $multifunction;
3179 my $addr = $pciaddr;
3180 $addr .= ".$j" if $multifunction;
3181 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3184 $devicestr .= "$rombar$xvga";
3185 $devicestr .= ",multifunction=on" if $multifunction;
3186 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3189 push @$devices, '-device', $devicestr;
3195 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3196 push @$devices, @usbdevices if @usbdevices;
3198 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3199 if (my $path = $conf->{"serial$i"}) {
3200 if ($path eq 'socket') {
3201 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3202 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3203 push @$devices, '-device', "isa-serial,chardev=serial$i";
3205 die "no such serial device\n" if ! -c
$path;
3206 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3207 push @$devices, '-device', "isa-serial,chardev=serial$i";
3213 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3214 if (my $path = $conf->{"parallel$i"}) {
3215 die "no such parallel device\n" if ! -c
$path;
3216 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3217 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3218 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3222 my $vmname = $conf->{name
} || "vm$vmid";
3224 push @$cmd, '-name', $vmname;
3227 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3228 $sockets = $conf->{sockets
} if $conf->{sockets
};
3230 my $cores = $conf->{cores
} || 1;
3232 my $maxcpus = $sockets * $cores;
3234 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3236 my $allowed_vcpus = $cpuinfo->{cpus
};
3238 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3239 if ($allowed_vcpus < $maxcpus);
3241 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3243 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3244 for (my $i = 2; $i <= $vcpus; $i++) {
3245 my $cpustr = print_cpu_device
($conf,$i);
3246 push @$cmd, '-device', $cpustr;
3251 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3253 push @$cmd, '-nodefaults';
3255 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3257 my $bootindex_hash = {};
3259 foreach my $o (split(//, $bootorder)) {
3260 $bootindex_hash->{$o} = $i*100;
3264 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3266 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3268 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3270 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3272 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3273 my $socket = vnc_socket
($vmid);
3274 push @$cmd, '-vnc', "unix:$socket,x509,password";
3276 push @$cmd, '-nographic';
3280 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3282 my $useLocaltime = $conf->{localtime};
3284 if ($winversion >= 5) { # windows
3285 $useLocaltime = 1 if !defined($conf->{localtime});
3287 # use time drift fix when acpi is enabled
3288 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3289 $tdf = 1 if !defined($conf->{tdf
});
3293 if ($winversion >= 6) {
3294 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3295 push @$cmd, '-no-hpet';
3298 push @$rtcFlags, 'driftfix=slew' if $tdf;
3301 push @$machineFlags, 'accel=tcg';
3304 if ($machine_type) {
3305 push @$machineFlags, "type=${machine_type}";
3308 if ($conf->{startdate
}) {
3309 push @$rtcFlags, "base=$conf->{startdate}";
3310 } elsif ($useLocaltime) {
3311 push @$rtcFlags, 'base=localtime';
3314 my $cpu = $kvm ?
"kvm64" : "qemu64";
3315 if (my $cputype = $conf->{cpu
}) {
3316 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3317 or die "Cannot parse cpu description: $cputype\n";
3318 $cpu = $cpuconf->{cputype
};
3319 $kvm_off = 1 if $cpuconf->{hidden
};
3321 if (defined(my $flags = $cpuconf->{flags
})) {
3322 push @$cpuFlags, split(";", $flags);
3326 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3328 push @$cpuFlags , '-x2apic'
3329 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3331 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3333 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3335 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3337 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3338 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3341 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3343 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3345 push @$cpuFlags, 'kvm=off' if $kvm_off;
3347 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3348 die "internal error"; # should not happen
3350 push @$cpuFlags, "vendor=${cpu_vendor}"
3351 if $cpu_vendor ne 'default';
3353 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3355 push @$cmd, '-cpu', $cpu;
3357 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3359 push @$cmd, '-S' if $conf->{freeze
};
3361 # set keyboard layout
3362 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3363 push @$cmd, '-k', $kb if $kb;
3366 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3367 #push @$cmd, '-soundhw', 'es1370';
3368 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3370 if($conf->{agent
}) {
3371 my $qgasocket = qmp_socket
($vmid, 1);
3372 my $pciaddr = print_pci_addr
("qga0", $bridges);
3373 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3374 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3375 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3383 for(my $i = 1; $i < $qxlnum; $i++){
3384 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3385 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3388 # assume other OS works like Linux
3389 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3390 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3394 my $pciaddr = print_pci_addr
("spice", $bridges);
3396 my $nodename = PVE
::INotify
::nodename
();
3397 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3398 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3399 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3400 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3401 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3403 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3405 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3406 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3407 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3410 # enable balloon by default, unless explicitly disabled
3411 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3412 $pciaddr = print_pci_addr
("balloon0", $bridges);
3413 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3416 if ($conf->{watchdog
}) {
3417 my $wdopts = parse_watchdog
($conf->{watchdog
});
3418 $pciaddr = print_pci_addr
("watchdog", $bridges);
3419 my $watchdog = $wdopts->{model
} || 'i6300esb';
3420 push @$devices, '-device', "$watchdog$pciaddr";
3421 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3425 my $scsicontroller = {};
3426 my $ahcicontroller = {};
3427 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3429 # Add iscsi initiator name if available
3430 if (my $initiator = get_initiator_name
()) {
3431 push @$devices, '-iscsi', "initiator-name=$initiator";
3434 foreach_drive
($conf, sub {
3435 my ($ds, $drive) = @_;
3437 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3438 push @$vollist, $drive->{file
};
3441 # ignore efidisk here, already added in bios/fw handling code above
3442 return if $drive->{interface
} eq 'efidisk';
3444 $use_virtio = 1 if $ds =~ m/^virtio/;
3446 if (drive_is_cdrom
($drive)) {
3447 if ($bootindex_hash->{d
}) {
3448 $drive->{bootindex
} = $bootindex_hash->{d
};
3449 $bootindex_hash->{d
} += 1;
3452 if ($bootindex_hash->{c
}) {
3453 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3454 $bootindex_hash->{c
} += 1;
3458 if($drive->{interface
} eq 'virtio'){
3459 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3462 if ($drive->{interface
} eq 'scsi') {
3464 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3466 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3467 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3470 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3471 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3472 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3473 } elsif ($drive->{iothread
}) {
3474 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3478 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3479 $queues = ",num_queues=$drive->{queues}";
3482 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3483 $scsicontroller->{$controller}=1;
3486 if ($drive->{interface
} eq 'sata') {
3487 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3488 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3489 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3490 $ahcicontroller->{$controller}=1;
3493 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3494 push @$devices, '-drive',$drive_cmd;
3495 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3498 for (my $i = 0; $i < $MAX_NETS; $i++) {
3499 next if !$conf->{"net$i"};
3500 my $d = parse_net
($conf->{"net$i"});
3503 $use_virtio = 1 if $d->{model
} eq 'virtio';
3505 if ($bootindex_hash->{n
}) {
3506 $d->{bootindex
} = $bootindex_hash->{n
};
3507 $bootindex_hash->{n
} += 1;
3510 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3511 push @$devices, '-netdev', $netdevfull;
3513 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3514 push @$devices, '-device', $netdevicefull;
3519 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3524 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3526 while (my ($k, $v) = each %$bridges) {
3527 $pciaddr = print_pci_addr
("pci.$k");
3528 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3533 if ($conf->{args
}) {
3534 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3538 push @$cmd, @$devices;
3539 push @$cmd, '-rtc', join(',', @$rtcFlags)
3540 if scalar(@$rtcFlags);
3541 push @$cmd, '-machine', join(',', @$machineFlags)
3542 if scalar(@$machineFlags);
3543 push @$cmd, '-global', join(',', @$globalFlags)
3544 if scalar(@$globalFlags);
3546 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3551 return "${var_run_tmpdir}/$vmid.vnc";
3557 my $res = vm_mon_cmd
($vmid, 'query-spice');
3559 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3563 my ($vmid, $qga) = @_;
3564 my $sockettype = $qga ?
'qga' : 'qmp';
3565 return "${var_run_tmpdir}/$vmid.$sockettype";
3570 return "${var_run_tmpdir}/$vmid.pid";
3573 sub vm_devices_list
{
3576 my $res = vm_mon_cmd
($vmid, 'query-pci');
3578 foreach my $pcibus (@$res) {
3579 foreach my $device (@{$pcibus->{devices
}}) {
3580 next if !$device->{'qdev_id'};
3581 if ($device->{'pci_bridge'}) {
3582 $devices->{$device->{'qdev_id'}} = 1;
3583 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3584 next if !$bridge_device->{'qdev_id'};
3585 $devices->{$bridge_device->{'qdev_id'}} = 1;
3586 $devices->{$device->{'qdev_id'}}++;
3589 $devices->{$device->{'qdev_id'}} = 1;
3594 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3595 foreach my $block (@$resblock) {
3596 if($block->{device
} =~ m/^drive-(\S+)/){
3601 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3602 foreach my $mice (@$resmice) {
3603 if ($mice->{name
} eq 'QEMU HID Tablet') {
3604 $devices->{tablet
} = 1;
3609 # for usb devices there is no query-usb
3610 # but we can iterate over the entries in
3611 # qom-list path=/machine/peripheral
3612 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3613 foreach my $per (@$resperipheral) {
3614 if ($per->{name
} =~ m/^usb\d+$/) {
3615 $devices->{$per->{name
}} = 1;
3623 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3625 my $q35 = machine_type_is_q35
($conf);
3627 my $devices_list = vm_devices_list
($vmid);
3628 return 1 if defined($devices_list->{$deviceid});
3630 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3632 if ($deviceid eq 'tablet') {
3634 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3636 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3638 die "usb hotplug currently not reliable\n";
3639 # since we can't reliably hot unplug all added usb devices
3640 # and usb passthrough disables live migration
3641 # we disable usb hotplugging for now
3642 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3644 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3646 qemu_iothread_add
($vmid, $deviceid, $device);
3648 qemu_driveadd
($storecfg, $vmid, $device);
3649 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3651 qemu_deviceadd
($vmid, $devicefull);
3652 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3654 eval { qemu_drivedel
($vmid, $deviceid); };
3659 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3662 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3663 my $pciaddr = print_pci_addr
($deviceid);
3664 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3666 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3668 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3669 qemu_iothread_add
($vmid, $deviceid, $device);
3670 $devicefull .= ",iothread=iothread-$deviceid";
3673 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3674 $devicefull .= ",num_queues=$device->{queues}";
3677 qemu_deviceadd
($vmid, $devicefull);
3678 qemu_deviceaddverify
($vmid, $deviceid);
3680 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3682 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3683 qemu_driveadd
($storecfg, $vmid, $device);
3685 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3686 eval { qemu_deviceadd
($vmid, $devicefull); };
3688 eval { qemu_drivedel
($vmid, $deviceid); };
3693 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3695 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3697 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3698 my $use_old_bios_files = undef;
3699 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3701 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3702 qemu_deviceadd
($vmid, $netdevicefull);
3703 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3705 eval { qemu_netdevdel
($vmid, $deviceid); };
3710 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3713 my $pciaddr = print_pci_addr
($deviceid);
3714 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3716 qemu_deviceadd
($vmid, $devicefull);
3717 qemu_deviceaddverify
($vmid, $deviceid);
3720 die "can't hotplug device '$deviceid'\n";
3726 # fixme: this should raise exceptions on error!
3727 sub vm_deviceunplug
{
3728 my ($vmid, $conf, $deviceid) = @_;
3730 my $devices_list = vm_devices_list
($vmid);
3731 return 1 if !defined($devices_list->{$deviceid});
3733 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3735 if ($deviceid eq 'tablet') {
3737 qemu_devicedel
($vmid, $deviceid);
3739 } elsif ($deviceid =~ m/^usb\d+$/) {
3741 die "usb hotplug currently not reliable\n";
3742 # when unplugging usb devices this way,
3743 # there may be remaining usb controllers/hubs
3744 # so we disable it for now
3745 qemu_devicedel
($vmid, $deviceid);
3746 qemu_devicedelverify
($vmid, $deviceid);
3748 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3750 qemu_devicedel
($vmid, $deviceid);
3751 qemu_devicedelverify
($vmid, $deviceid);
3752 qemu_drivedel
($vmid, $deviceid);
3753 qemu_iothread_del
($conf, $vmid, $deviceid);
3755 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3757 qemu_devicedel
($vmid, $deviceid);
3758 qemu_devicedelverify
($vmid, $deviceid);
3759 qemu_iothread_del
($conf, $vmid, $deviceid);
3761 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3763 qemu_devicedel
($vmid, $deviceid);
3764 qemu_drivedel
($vmid, $deviceid);
3765 qemu_deletescsihw
($conf, $vmid, $deviceid);
3767 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3769 qemu_devicedel
($vmid, $deviceid);
3770 qemu_devicedelverify
($vmid, $deviceid);
3771 qemu_netdevdel
($vmid, $deviceid);
3774 die "can't unplug device '$deviceid'\n";
3780 sub qemu_deviceadd
{
3781 my ($vmid, $devicefull) = @_;
3783 $devicefull = "driver=".$devicefull;
3784 my %options = split(/[=,]/, $devicefull);
3786 vm_mon_cmd
($vmid, "device_add" , %options);
3789 sub qemu_devicedel
{
3790 my ($vmid, $deviceid) = @_;
3792 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3795 sub qemu_iothread_add
{
3796 my($vmid, $deviceid, $device) = @_;
3798 if ($device->{iothread
}) {
3799 my $iothreads = vm_iothreads_list
($vmid);
3800 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3804 sub qemu_iothread_del
{
3805 my($conf, $vmid, $deviceid) = @_;
3807 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3808 if ($device->{iothread
}) {
3809 my $iothreads = vm_iothreads_list
($vmid);
3810 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3814 sub qemu_objectadd
{
3815 my($vmid, $objectid, $qomtype) = @_;
3817 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3822 sub qemu_objectdel
{
3823 my($vmid, $objectid) = @_;
3825 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3831 my ($storecfg, $vmid, $device) = @_;
3833 my $drive = print_drive_full
($storecfg, $vmid, $device);
3834 $drive =~ s/\\/\\\\/g;
3835 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3837 # If the command succeeds qemu prints: "OK
"
3838 return 1 if $ret =~ m/OK/s;
3840 die "adding drive failed
: $ret\n";
3844 my($vmid, $deviceid) = @_;
3846 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3849 return 1 if $ret eq "";
3851 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3852 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3854 die "deleting drive
$deviceid failed
: $ret\n";
3857 sub qemu_deviceaddverify {
3858 my ($vmid, $deviceid) = @_;
3860 for (my $i = 0; $i <= 5; $i++) {
3861 my $devices_list = vm_devices_list($vmid);
3862 return 1 if defined($devices_list->{$deviceid});
3866 die "error on hotplug device
'$deviceid'\n";
3870 sub qemu_devicedelverify {
3871 my ($vmid, $deviceid) = @_;
3873 # need to verify that the device is correctly removed as device_del
3874 # is async and empty return is not reliable
3876 for (my $i = 0; $i <= 5; $i++) {
3877 my $devices_list = vm_devices_list($vmid);
3878 return 1 if !defined($devices_list->{$deviceid});
3882 die "error on hot-unplugging device
'$deviceid'\n";
3885 sub qemu_findorcreatescsihw {
3886 my ($storecfg, $conf, $vmid, $device) = @_;
3888 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3890 my $scsihwid="$controller_prefix$controller";
3891 my $devices_list = vm_devices_list($vmid);
3893 if(!defined($devices_list->{$scsihwid})) {
3894 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3900 sub qemu_deletescsihw {
3901 my ($conf, $vmid, $opt) = @_;
3903 my $device = parse_drive($opt, $conf->{$opt});
3905 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3906 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3910 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3912 my $devices_list = vm_devices_list($vmid);
3913 foreach my $opt (keys %{$devices_list}) {
3914 if (PVE::QemuServer::is_valid_drivename($opt)) {
3915 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3916 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3922 my $scsihwid="scsihw
$controller";
3924 vm_deviceunplug($vmid, $conf, $scsihwid);
3929 sub qemu_add_pci_bridge {
3930 my ($storecfg, $conf, $vmid, $device) = @_;
3936 print_pci_addr($device, $bridges);
3938 while (my ($k, $v) = each %$bridges) {
3941 return 1 if !defined($bridgeid) || $bridgeid < 1;
3943 my $bridge = "pci
.$bridgeid";
3944 my $devices_list = vm_devices_list($vmid);
3946 if (!defined($devices_list->{$bridge})) {
3947 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3953 sub qemu_set_link_status {
3954 my ($vmid, $device, $up) = @_;
3956 vm_mon_cmd($vmid, "set_link
", name => $device,
3957 up => $up ? JSON::true : JSON::false);
3960 sub qemu_netdevadd {
3961 my ($vmid, $conf, $device, $deviceid) = @_;
3963 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3964 my %options = split(/[=,]/, $netdev);
3966 vm_mon_cmd($vmid, "netdev_add
", %options);
3970 sub qemu_netdevdel {
3971 my ($vmid, $deviceid) = @_;
3973 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
3976 sub qemu_usb_hotplug {
3977 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3981 # remove the old one first
3982 vm_deviceunplug($vmid, $conf, $deviceid);
3984 # check if xhci controller is necessary and available
3985 if ($device->{usb3}) {
3987 my $devicelist = vm_devices_list($vmid);
3989 if (!$devicelist->{xhci}) {
3990 my $pciaddr = print_pci_addr("xhci
");
3991 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
3994 my $d = parse_usb_device($device->{host});
3995 $d->{usb3} = $device->{usb3};
3998 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4001 sub qemu_cpu_hotplug {
4002 my ($vmid, $conf, $vcpus) = @_;
4004 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4007 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4008 $sockets = $conf->{sockets} if $conf->{sockets};
4009 my $cores = $conf->{cores} || 1;
4010 my $maxcpus = $sockets * $cores;
4012 $vcpus = $maxcpus if !$vcpus;
4014 die "you can
't add more vcpus than maxcpus\n"
4015 if $vcpus > $maxcpus;
4017 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4019 if ($vcpus < $currentvcpus) {
4021 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4023 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4024 qemu_devicedel($vmid, "cpu$i");
4026 my $currentrunningvcpus = undef;
4028 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4029 last if scalar(@{$currentrunningvcpus}) == $i-1;
4030 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4034 #update conf after each succesfull cpu unplug
4035 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4036 PVE::QemuConfig->write_config($vmid, $conf);
4039 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4045 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4046 die "vcpus in running vm does not match its configuration\n"
4047 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4049 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4051 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4052 my $cpustr = print_cpu_device($conf, $i);
4053 qemu_deviceadd($vmid, $cpustr);
4056 my $currentrunningvcpus = undef;
4058 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4059 last if scalar(@{$currentrunningvcpus}) == $i;
4060 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4064 #update conf after each succesfull cpu hotplug
4065 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4066 PVE::QemuConfig->write_config($vmid, $conf);
4070 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4071 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4076 sub qemu_block_set_io_throttle {
4077 my ($vmid, $deviceid,
4078 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4079 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4080 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4081 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4083 return if !check_running($vmid) ;
4085 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4087 bps_rd => int($bps_rd),
4088 bps_wr => int($bps_wr),
4090 iops_rd => int($iops_rd),
4091 iops_wr => int($iops_wr),
4092 bps_max => int($bps_max),
4093 bps_rd_max => int($bps_rd_max),
4094 bps_wr_max => int($bps_wr_max),
4095 iops_max => int($iops_max),
4096 iops_rd_max => int($iops_rd_max),
4097 iops_wr_max => int($iops_wr_max),
4098 bps_max_length => int($bps_max_length),
4099 bps_rd_max_length => int($bps_rd_max_length),
4100 bps_wr_max_length => int($bps_wr_max_length),
4101 iops_max_length => int($iops_max_length),
4102 iops_rd_max_length => int($iops_rd_max_length),
4103 iops_wr_max_length => int($iops_wr_max_length),
4108 # old code, only used to shutdown old VM after update
4110 my ($fh, $timeout) = @_;
4112 my $sel = new IO::Select;
4119 while (scalar (@ready = $sel->can_read($timeout))) {
4121 if ($count = $fh->sysread($buf, 8192)) {
4122 if ($buf =~ /^(.*)\(qemu\) $/s) {
4129 if (!defined($count)) {
4136 die "monitor read timeout\n" if !scalar(@ready);
4141 # old code, only used to shutdown old VM after update
4142 sub vm_monitor_command {
4143 my ($vmid, $cmdstr, $nocheck) = @_;
4148 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4150 my $sname = "${var_run_tmpdir}/$vmid.mon";
4152 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
4153 die "unable to connect to VM $vmid socket - $!\n";
4157 # hack: migrate sometime blocks the monitor (when migrate_downtime
4159 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4160 $timeout = 60*60; # 1 hour
4164 my $data = __read_avail($sock, $timeout);
4166 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
4167 die "got unexpected qemu monitor banner\n";
4170 my $sel = new IO::Select;
4173 if (!scalar(my @ready = $sel->can_write($timeout))) {
4174 die "monitor write error - timeout";
4177 my $fullcmd = "$cmdstr\r";
4179 # syslog('info
', "VM $vmid monitor command: $cmdstr");
4182 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
4183 die "monitor write error - $!";
4186 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
4190 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4191 $timeout = 60*60; # 1 hour
4192 } elsif ($cmdstr =~ m/^(eject|change)/) {
4193 $timeout = 60; # note: cdrom mount command is slow
4195 if ($res = __read_avail($sock, $timeout)) {
4197 my @lines = split("\r?\n", $res);
4199 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
4201 $res = join("\n", @lines);
4209 syslog("err", "VM $vmid monitor command failed - $err");
4216 sub qemu_block_resize {
4217 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4219 my $running = check_running($vmid);
4221 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4223 return if !$running;
4225 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4229 sub qemu_volume_snapshot {
4230 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4232 my $running = check_running($vmid);
4234 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4235 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4237 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4241 sub qemu_volume_snapshot_delete {
4242 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4244 my $running = check_running($vmid);
4246 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4247 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4249 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4253 sub set_migration_caps {
4259 "auto-converge" => 1,
4261 "x-rdma-pin-all" => 0,
4266 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4268 for my $supported_capability (@$supported_capabilities) {
4270 capability => $supported_capability->{capability},
4271 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4275 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4278 my $fast_plug_option = {
4286 'vmstatestorage
' => 1,
4289 # hotplug changes in [PENDING]
4290 # $selection hash can be used to only apply specified options, for
4291 # example: { cores => 1 } (only apply changed 'cores
')
4292 # $errors ref is used to return error messages
4293 sub vmconfig_hotplug_pending {
4294 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4296 my $defaults = load_defaults();
4298 # commit values which do not have any impact on running VM first
4299 # Note: those option cannot raise errors, we we do not care about
4300 # $selection and always apply them.
4302 my $add_error = sub {
4303 my ($opt, $msg) = @_;
4304 $errors->{$opt} = "hotplug problem - $msg";
4308 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4309 if ($fast_plug_option->{$opt}) {
4310 $conf->{$opt} = $conf->{pending}->{$opt};
4311 delete $conf->{pending}->{$opt};
4317 PVE::QemuConfig->write_config($vmid, $conf);
4318 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4321 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4323 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4324 while (my ($opt, $force) = each %$pending_delete_hash) {
4325 next if $selection && !$selection->{$opt};
4327 if ($opt eq 'hotplug
') {
4328 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4329 } elsif ($opt eq 'tablet
') {
4330 die "skip\n" if !$hotplug_features->{usb};
4331 if ($defaults->{tablet}) {
4332 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4334 vm_deviceunplug($vmid, $conf, $opt);
4336 } elsif ($opt =~ m/^usb\d+/) {
4338 # since we cannot reliably hot unplug usb devices
4339 # we are disabling it
4340 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4341 vm_deviceunplug($vmid, $conf, $opt);
4342 } elsif ($opt eq 'vcpus
') {
4343 die "skip\n" if !$hotplug_features->{cpu};
4344 qemu_cpu_hotplug($vmid, $conf, undef);
4345 } elsif ($opt eq 'balloon
') {
4346 # enable balloon device is not hotpluggable
4347 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4348 } elsif ($fast_plug_option->{$opt}) {
4350 } elsif ($opt =~ m/^net(\d+)$/) {
4351 die "skip\n" if !$hotplug_features->{network};
4352 vm_deviceunplug($vmid, $conf, $opt);
4353 } elsif (is_valid_drivename($opt)) {
4354 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4355 vm_deviceunplug($vmid, $conf, $opt);
4356 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4357 } elsif ($opt =~ m/^memory$/) {
4358 die "skip\n" if !$hotplug_features->{memory};
4359 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4360 } elsif ($opt eq 'cpuunits
') {
4361 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4362 } elsif ($opt eq 'cpulimit
') {
4363 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4369 &$add_error($opt, $err) if $err ne "skip\n";
4371 # save new config if hotplug was successful
4372 delete $conf->{$opt};
4373 vmconfig_undelete_pending_option($conf, $opt);
4374 PVE::QemuConfig->write_config($vmid, $conf);
4375 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4379 foreach my $opt (keys %{$conf->{pending}}) {
4380 next if $selection && !$selection->{$opt};
4381 my $value = $conf->{pending}->{$opt};
4383 if ($opt eq 'hotplug
') {
4384 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4385 } elsif ($opt eq 'tablet
') {
4386 die "skip\n" if !$hotplug_features->{usb};
4388 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4389 } elsif ($value == 0) {
4390 vm_deviceunplug($vmid, $conf, $opt);
4392 } elsif ($opt =~ m/^usb\d+$/) {
4394 # since we cannot reliably hot unplug usb devices
4395 # we are disabling it
4396 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4397 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4398 die "skip\n" if !$d;
4399 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4400 } elsif ($opt eq 'vcpus
') {
4401 die "skip\n" if !$hotplug_features->{cpu};
4402 qemu_cpu_hotplug($vmid, $conf, $value);
4403 } elsif ($opt eq 'balloon
') {
4404 # enable/disable balloning device is not hotpluggable
4405 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4406 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4407 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4409 # allow manual ballooning if shares is set to zero
4410 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4411 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4412 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4414 } elsif ($opt =~ m/^net(\d+)$/) {
4415 # some changes can be done without hotplug
4416 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4417 $vmid, $opt, $value);
4418 } elsif (is_valid_drivename($opt)) {
4419 # some changes can be done without hotplug
4420 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4421 $vmid, $opt, $value, 1);
4422 } elsif ($opt =~ m/^memory$/) { #dimms
4423 die "skip\n" if !$hotplug_features->{memory};
4424 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4425 } elsif ($opt eq 'cpuunits
') {
4426 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4427 } elsif ($opt eq 'cpulimit
') {
4428 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4429 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4431 die "skip\n"; # skip non-hot-pluggable options
4435 &$add_error($opt, $err) if $err ne "skip\n";
4437 # save new config if hotplug was successful
4438 $conf->{$opt} = $value;
4439 delete $conf->{pending}->{$opt};
4440 PVE::QemuConfig->write_config($vmid, $conf);
4441 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4446 sub try_deallocate_drive {
4447 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4449 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4450 my $volid = $drive->{file};
4451 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4452 my $sid = PVE::Storage::parse_volume_id($volid);
4453 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4455 # check if the disk is really unused
4456 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4457 if is_volume_in_use($storecfg, $conf, $key, $volid);
4458 PVE::Storage::vdisk_free($storecfg, $volid);
4461 # If vm is not owner of this disk remove from config
4469 sub vmconfig_delete_or_detach_drive {
4470 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4472 my $drive = parse_drive($opt, $conf->{$opt});
4474 my $rpcenv = PVE::RPCEnvironment::get();
4475 my $authuser = $rpcenv->get_user();
4478 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4479 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4481 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4485 sub vmconfig_apply_pending {
4486 my ($vmid, $conf, $storecfg) = @_;
4490 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4491 while (my ($opt, $force) = each %$pending_delete_hash) {
4492 die "internal error" if $opt =~ m/^unused/;
4493 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4494 if (!defined($conf->{$opt})) {
4495 vmconfig_undelete_pending_option($conf, $opt);
4496 PVE::QemuConfig->write_config($vmid, $conf);
4497 } elsif (is_valid_drivename($opt)) {
4498 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4499 vmconfig_undelete_pending_option($conf, $opt);
4500 delete $conf->{$opt};
4501 PVE::QemuConfig->write_config($vmid, $conf);
4503 vmconfig_undelete_pending_option($conf, $opt);
4504 delete $conf->{$opt};
4505 PVE::QemuConfig->write_config($vmid, $conf);
4509 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4511 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4512 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4514 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4515 # skip if nothing changed
4516 } elsif (is_valid_drivename($opt)) {
4517 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4518 if defined($conf->{$opt});
4519 $conf->{$opt} = $conf->{pending}->{$opt};
4521 $conf->{$opt} = $conf->{pending}->{$opt};
4524 delete $conf->{pending}->{$opt};
4525 PVE::QemuConfig->write_config($vmid, $conf);
4529 my $safe_num_ne = sub {
4532 return 0 if !defined($a) && !defined($b);
4533 return 1 if !defined($a);
4534 return 1 if !defined($b);
4539 my $safe_string_ne = sub {
4542 return 0 if !defined($a) && !defined($b);
4543 return 1 if !defined($a);
4544 return 1 if !defined($b);
4549 sub vmconfig_update_net {
4550 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4552 my $newnet = parse_net($value);
4554 if ($conf->{$opt}) {
4555 my $oldnet = parse_net($conf->{$opt});
4557 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4558 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4559 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4560 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4562 # for non online change, we try to hot-unplug
4563 die "skip\n" if !$hotplug;
4564 vm_deviceunplug($vmid, $conf, $opt);
4567 die "internal error" if $opt !~ m/net(\d+)/;
4568 my $iface = "tap${vmid}i$1";
4570 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4571 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4572 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4573 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4574 PVE::Network::tap_unplug($iface);
4575 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4576 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4577 # Rate can be applied on its own but any change above needs to
4578 # include the rate in tap_plug since OVS resets everything.
4579 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4582 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4583 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4591 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4597 sub vmconfig_update_disk {
4598 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4600 # fixme: do we need force?
4602 my $drive = parse_drive($opt, $value);
4604 if ($conf->{$opt}) {
4606 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4608 my $media = $drive->{media} || 'disk
';
4609 my $oldmedia = $old_drive->{media} || 'disk
';
4610 die "unable to change media type\n" if $media ne $oldmedia;
4612 if (!drive_is_cdrom($old_drive)) {
4614 if ($drive->{file} ne $old_drive->{file}) {
4616 die "skip\n" if !$hotplug;
4618 # unplug and register as unused
4619 vm_deviceunplug($vmid, $conf, $opt);
4620 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4623 # update existing disk
4625 # skip non hotpluggable value
4626 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4627 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4628 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4629 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4634 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4635 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4636 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4637 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4638 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4639 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4640 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4641 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4642 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4643 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4644 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4645 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4646 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4647 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4648 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4649 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4650 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4651 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4653 qemu_block_set_io_throttle($vmid,"drive-$opt",
4654 ($drive->{mbps} || 0)*1024*1024,
4655 ($drive->{mbps_rd} || 0)*1024*1024,
4656 ($drive->{mbps_wr} || 0)*1024*1024,
4657 $drive->{iops} || 0,
4658 $drive->{iops_rd} || 0,
4659 $drive->{iops_wr} || 0,
4660 ($drive->{mbps_max} || 0)*1024*1024,
4661 ($drive->{mbps_rd_max} || 0)*1024*1024,
4662 ($drive->{mbps_wr_max} || 0)*1024*1024,
4663 $drive->{iops_max} || 0,
4664 $drive->{iops_rd_max} || 0,
4665 $drive->{iops_wr_max} || 0,
4666 $drive->{bps_max_length} || 1,
4667 $drive->{bps_rd_max_length} || 1,
4668 $drive->{bps_wr_max_length} || 1,
4669 $drive->{iops_max_length} || 1,
4670 $drive->{iops_rd_max_length} || 1,
4671 $drive->{iops_wr_max_length} || 1);
4680 if ($drive->{file} eq 'none
') {
4681 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4683 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4684 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4685 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4693 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4695 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4696 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4700 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4701 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4703 PVE::QemuConfig->lock_config($vmid, sub {
4704 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4706 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4708 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4710 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4712 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4713 vmconfig_apply_pending($vmid, $conf, $storecfg);
4714 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4717 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4719 my $defaults = load_defaults();
4721 # set environment variable useful inside network script
4722 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4724 my $local_volumes = {};
4726 if ($targetstorage) {
4727 foreach_drive($conf, sub {
4728 my ($ds, $drive) = @_;
4730 return if drive_is_cdrom($drive);
4732 my $volid = $drive->{file};
4736 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4738 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4739 return if $scfg->{shared};
4740 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4745 foreach my $opt (sort keys %$local_volumes) {
4747 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4748 my $drive = parse_drive($opt, $conf->{$opt});
4750 #if remote storage is specified, use default format
4751 if ($targetstorage && $targetstorage ne "1") {
4752 $storeid = $targetstorage;
4753 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4754 $format = $defFormat;
4756 #else we use same format than original
4757 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4758 $format = qemu_img_format($scfg, $volid);
4761 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4762 my $newdrive = $drive;
4763 $newdrive->{format} = $format;
4764 $newdrive->{file} = $newvolid;
4765 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4766 $local_volumes->{$opt} = $drivestr;
4767 #pass drive to conf for command line
4768 $conf->{$opt} = $drivestr;
4772 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4774 my $migrate_port = 0;
4777 if ($statefile eq 'tcp
') {
4778 my $localip = "localhost";
4779 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4780 my $nodename = PVE::INotify::nodename();
4782 if (!defined($migration_type)) {
4783 if (defined($datacenterconf->{migration}->{type})) {
4784 $migration_type = $datacenterconf->{migration}->{type};
4786 $migration_type = 'secure
';
4790 if ($migration_type eq 'insecure
') {
4791 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4792 if ($migrate_network_addr) {
4793 $localip = $migrate_network_addr;
4795 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4798 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4801 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4802 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4803 $migrate_uri = "tcp:${localip}:${migrate_port}";
4804 push @$cmd, '-incoming
', $migrate_uri;
4807 } elsif ($statefile eq 'unix
') {
4808 # should be default for secure migrations as a ssh TCP forward
4809 # tunnel is not deterministic reliable ready and fails regurarly
4810 # to set up in time, so use UNIX socket forwards
4811 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4812 unlink $socket_addr;
4814 $migrate_uri = "unix:$socket_addr";
4816 push @$cmd, '-incoming
', $migrate_uri;
4820 push @$cmd, '-loadstate
', $statefile;
4827 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4828 my $d = parse_hostpci($conf->{"hostpci$i"});
4830 my $pcidevices = $d->{pciid};
4831 foreach my $pcidevice (@$pcidevices) {
4832 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4834 my $info = pci_device_info("0000:$pciid");
4835 die "IOMMU not present\n" if !check_iommu_support();
4836 die "no pci device info for device '$pciid'\n" if !$info;
4837 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4838 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4842 PVE::Storage::activate_volumes($storecfg, $vollist);
4844 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4846 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4847 eval { run_command($cmd); };
4850 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4851 : $defaults->{cpuunits};
4853 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4854 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4857 Slice => 'qemu
.slice
',
4859 CPUShares => $cpuunits
4862 if (my $cpulimit = $conf->{cpulimit}) {
4863 $properties{CPUQuota} = int($cpulimit * 100);
4865 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4867 if ($conf->{hugepages}) {
4870 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4871 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4873 PVE::QemuServer::Memory::hugepages_mount();
4874 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4877 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4878 run_command($cmd, %run_params);
4882 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4886 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4888 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4892 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4893 run_command($cmd, %run_params);
4898 # deactivate volumes if start fails
4899 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4900 die "start failed: $err";
4903 print "migration listens on $migrate_uri\n" if $migrate_uri;
4905 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4906 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4910 #start nbd server for storage migration
4911 if ($targetstorage) {
4912 my $nodename = PVE::INotify::nodename();
4913 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4914 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4915 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4916 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4918 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4920 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4922 foreach my $opt (sort keys %$local_volumes) {
4923 my $volid = $local_volumes->{$opt};
4924 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4925 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4926 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4930 if ($migratedfrom) {
4932 set_migration_caps($vmid);
4937 print "spice listens on port $spice_port\n";
4938 if ($spice_ticket) {
4939 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4940 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4945 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4946 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4947 if $conf->{balloon};
4950 foreach my $opt (keys %$conf) {
4951 next if $opt !~ m/^net\d+$/;
4952 my $nicconf = parse_net($conf->{$opt});
4953 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4957 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4958 path => "machine/peripheral/balloon0",
4959 property => "guest-stats-polling-interval",
4960 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4966 my ($vmid, $execute, %params) = @_;
4968 my $cmd = { execute => $execute, arguments => \%params };
4969 vm_qmp_command($vmid, $cmd);
4972 sub vm_mon_cmd_nocheck {
4973 my ($vmid, $execute, %params) = @_;
4975 my $cmd = { execute => $execute, arguments => \%params };
4976 vm_qmp_command($vmid, $cmd, 1);
4979 sub vm_qmp_command {
4980 my ($vmid, $cmd, $nocheck) = @_;
4985 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4986 $timeout = $cmd->{arguments}->{timeout};
4987 delete $cmd->{arguments}->{timeout};
4991 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4992 my $sname = qmp_socket($vmid);
4993 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4994 my $qmpclient = PVE::QMPClient->new();
4996 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4997 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
4998 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
4999 if scalar(%{$cmd->{arguments}});
5000 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
5002 die "unable to
open monitor
socket\n";
5006 syslog("err
", "VM
$vmid qmp command failed
- $err");
5013 sub vm_human_monitor_command {
5014 my ($vmid, $cmdline) = @_;
5019 execute => 'human-monitor-command',
5020 arguments => { 'command-line' => $cmdline},
5023 return vm_qmp_command($vmid, $cmd);
5026 sub vm_commandline {
5027 my ($storecfg, $vmid) = @_;
5029 my $conf = PVE::QemuConfig->load_config($vmid);
5031 my $defaults = load_defaults();
5033 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5035 return PVE::Tools::cmd2string($cmd);
5039 my ($vmid, $skiplock) = @_;
5041 PVE::QemuConfig->lock_config($vmid, sub {
5043 my $conf = PVE::QemuConfig->load_config($vmid);
5045 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5047 vm_mon_cmd($vmid, "system_reset
");
5051 sub get_vm_volumes {
5055 foreach_volid($conf, sub {
5056 my ($volid, $attr) = @_;
5058 return if $volid =~ m|^/|;
5060 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5063 push @$vollist, $volid;
5069 sub vm_stop_cleanup {
5070 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5075 my $vollist = get_vm_volumes($conf);
5076 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5079 foreach my $ext (qw(mon qmp pid vnc qga)) {
5080 unlink "/var/run/qemu-server/${vmid}.$ext";
5083 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5085 warn $@ if $@; # avoid errors - just warn
5088 # Note: use $nockeck to skip tests if VM configuration file exists.
5089 # We need that when migration VMs to other nodes (files already moved)
5090 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5092 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5094 $force = 1 if !defined($force) && !$shutdown;
5097 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5098 kill 15, $pid if $pid;
5099 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5100 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5104 PVE
::QemuConfig-
>lock_config($vmid, sub {
5106 my $pid = check_running
($vmid, $nocheck);
5111 $conf = PVE
::QemuConfig-
>load_config($vmid);
5112 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5113 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5114 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5115 $timeout = $opts->{down
} if $opts->{down
};
5119 $timeout = 60 if !defined($timeout);
5123 if (defined($conf) && $conf->{agent
}) {
5124 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5126 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5129 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5136 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5141 if ($count >= $timeout) {
5143 warn "VM still running - terminating now with SIGTERM\n";
5146 die "VM quit/powerdown failed - got timeout\n";
5149 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5154 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5157 die "VM quit/powerdown failed\n";
5165 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5170 if ($count >= $timeout) {
5171 warn "VM still running - terminating now with SIGKILL\n";
5176 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5181 my ($vmid, $skiplock) = @_;
5183 PVE
::QemuConfig-
>lock_config($vmid, sub {
5185 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5187 PVE
::QemuConfig-
>check_lock($conf)
5188 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5190 vm_mon_cmd
($vmid, "stop");
5195 my ($vmid, $skiplock, $nocheck) = @_;
5197 PVE
::QemuConfig-
>lock_config($vmid, sub {
5201 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5203 PVE
::QemuConfig-
>check_lock($conf)
5204 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5206 vm_mon_cmd
($vmid, "cont");
5209 vm_mon_cmd_nocheck
($vmid, "cont");
5215 my ($vmid, $skiplock, $key) = @_;
5217 PVE
::QemuConfig-
>lock_config($vmid, sub {
5219 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5221 # there is no qmp command, so we use the human monitor command
5222 vm_human_monitor_command
($vmid, "sendkey $key");
5227 my ($storecfg, $vmid, $skiplock) = @_;
5229 PVE
::QemuConfig-
>lock_config($vmid, sub {
5231 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5233 if (!check_running
($vmid)) {
5234 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5236 die "VM $vmid is running - destroy failed\n";
5244 my ($filename, $buf) = @_;
5246 my $fh = IO
::File-
>new($filename, "w");
5247 return undef if !$fh;
5249 my $res = print $fh $buf;
5256 sub pci_device_info
{
5261 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5262 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5264 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5265 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5267 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5268 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5270 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5271 return undef if !defined($product) || $product !~ s/^0x//;
5276 product
=> $product,
5282 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5291 my $name = $dev->{name
};
5293 my $fn = "$pcisysfs/devices/$name/reset";
5295 return file_write
($fn, "1");
5298 sub pci_dev_bind_to_vfio
{
5301 my $name = $dev->{name
};
5303 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5305 if (!-d
$vfio_basedir) {
5306 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5308 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5310 my $testdir = "$vfio_basedir/$name";
5311 return 1 if -d
$testdir;
5313 my $data = "$dev->{vendor} $dev->{product}";
5314 return undef if !file_write
("$vfio_basedir/new_id", $data);
5316 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5317 if (!file_write
($fn, $name)) {
5318 return undef if -f
$fn;
5321 $fn = "$vfio_basedir/bind";
5322 if (! -d
$testdir) {
5323 return undef if !file_write
($fn, $name);
5329 sub pci_dev_group_bind_to_vfio
{
5332 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5334 if (!-d
$vfio_basedir) {
5335 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5337 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5339 # get IOMMU group devices
5340 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5341 my @devs = grep /^0000:/, readdir($D);
5344 foreach my $pciid (@devs) {
5345 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5347 # pci bridges, switches or root ports are not supported
5348 # they have a pci_bus subdirectory so skip them
5349 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5351 my $info = pci_device_info
($1);
5352 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5358 # vzdump restore implementaion
5360 sub tar_archive_read_firstfile
{
5361 my $archive = shift;
5363 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5365 # try to detect archive type first
5366 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5367 die "unable to open file '$archive'\n";
5368 my $firstfile = <$fh>;
5372 die "ERROR: archive contaions no data\n" if !$firstfile;
5378 sub tar_restore_cleanup
{
5379 my ($storecfg, $statfile) = @_;
5381 print STDERR
"starting cleanup\n";
5383 if (my $fd = IO
::File-
>new($statfile, "r")) {
5384 while (defined(my $line = <$fd>)) {
5385 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5388 if ($volid =~ m
|^/|) {
5389 unlink $volid || die 'unlink failed\n';
5391 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5393 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5395 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5397 print STDERR
"unable to parse line in statfile - $line";
5404 sub restore_archive
{
5405 my ($archive, $vmid, $user, $opts) = @_;
5407 my $format = $opts->{format
};
5410 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5411 $format = 'tar' if !$format;
5413 } elsif ($archive =~ m/\.tar$/) {
5414 $format = 'tar' if !$format;
5415 } elsif ($archive =~ m/.tar.lzo$/) {
5416 $format = 'tar' if !$format;
5418 } elsif ($archive =~ m/\.vma$/) {
5419 $format = 'vma' if !$format;
5420 } elsif ($archive =~ m/\.vma\.gz$/) {
5421 $format = 'vma' if !$format;
5423 } elsif ($archive =~ m/\.vma\.lzo$/) {
5424 $format = 'vma' if !$format;
5427 $format = 'vma' if !$format; # default
5430 # try to detect archive format
5431 if ($format eq 'tar') {
5432 return restore_tar_archive
($archive, $vmid, $user, $opts);
5434 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5438 sub restore_update_config_line
{
5439 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5441 return if $line =~ m/^\#qmdump\#/;
5442 return if $line =~ m/^\#vzdump\#/;
5443 return if $line =~ m/^lock:/;
5444 return if $line =~ m/^unused\d+:/;
5445 return if $line =~ m/^parent:/;
5446 return if $line =~ m/^template:/; # restored VM is never a template
5448 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5449 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5450 # try to convert old 1.X settings
5451 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5452 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5453 my ($model, $macaddr) = split(/\=/, $devconfig);
5454 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5457 bridge
=> "vmbr$ind",
5458 macaddr
=> $macaddr,
5460 my $netstr = print_net
($net);
5462 print $outfd "net$cookie->{netcount}: $netstr\n";
5463 $cookie->{netcount
}++;
5465 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5466 my ($id, $netstr) = ($1, $2);
5467 my $net = parse_net
($netstr);
5468 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5469 $netstr = print_net
($net);
5470 print $outfd "$id: $netstr\n";
5471 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5474 my $di = parse_drive
($virtdev, $value);
5475 if (defined($di->{backup
}) && !$di->{backup
}) {
5476 print $outfd "#$line";
5477 } elsif ($map->{$virtdev}) {
5478 delete $di->{format
}; # format can change on restore
5479 $di->{file
} = $map->{$virtdev};
5480 $value = print_drive
($vmid, $di);
5481 print $outfd "$virtdev: $value\n";
5485 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5486 my ($uuid, $uuid_str);
5487 UUID
::generate
($uuid);
5488 UUID
::unparse
($uuid, $uuid_str);
5489 my $smbios1 = parse_smbios1
($2);
5490 $smbios1->{uuid
} = $uuid_str;
5491 print $outfd $1.print_smbios1
($smbios1)."\n";
5498 my ($cfg, $vmid) = @_;
5500 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5502 my $volid_hash = {};
5503 foreach my $storeid (keys %$info) {
5504 foreach my $item (@{$info->{$storeid}}) {
5505 next if !($item->{volid
} && $item->{size
});
5506 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5507 $volid_hash->{$item->{volid
}} = $item;
5514 sub is_volume_in_use
{
5515 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5517 my $path = PVE
::Storage
::path
($storecfg, $volid);
5519 my $scan_config = sub {
5520 my ($cref, $snapname) = @_;
5522 foreach my $key (keys %$cref) {
5523 my $value = $cref->{$key};
5524 if (is_valid_drivename
($key)) {
5525 next if $skip_drive && $key eq $skip_drive;
5526 my $drive = parse_drive
($key, $value);
5527 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5528 return 1 if $volid eq $drive->{file
};
5529 if ($drive->{file
} =~ m!^/!) {
5530 return 1 if $drive->{file
} eq $path;
5532 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5534 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5536 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5544 return 1 if &$scan_config($conf);
5548 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5549 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5555 sub update_disksize
{
5556 my ($vmid, $conf, $volid_hash) = @_;
5560 # used and unused disks
5561 my $referenced = {};
5563 # Note: it is allowed to define multiple storages with same path (alias), so
5564 # we need to check both 'volid' and real 'path' (two different volid can point
5565 # to the same path).
5567 my $referencedpath = {};
5570 foreach my $opt (keys %$conf) {
5571 if (is_valid_drivename
($opt)) {
5572 my $drive = parse_drive
($opt, $conf->{$opt});
5573 my $volid = $drive->{file
};
5576 $referenced->{$volid} = 1;
5577 if ($volid_hash->{$volid} &&
5578 (my $path = $volid_hash->{$volid}->{path
})) {
5579 $referencedpath->{$path} = 1;
5582 next if drive_is_cdrom
($drive);
5583 next if !$volid_hash->{$volid};
5585 $drive->{size
} = $volid_hash->{$volid}->{size
};
5586 my $new = print_drive
($vmid, $drive);
5587 if ($new ne $conf->{$opt}) {
5589 $conf->{$opt} = $new;
5594 # remove 'unusedX' entry if volume is used
5595 foreach my $opt (keys %$conf) {
5596 next if $opt !~ m/^unused\d+$/;
5597 my $volid = $conf->{$opt};
5598 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5599 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5601 delete $conf->{$opt};
5604 $referenced->{$volid} = 1;
5605 $referencedpath->{$path} = 1 if $path;
5608 foreach my $volid (sort keys %$volid_hash) {
5609 next if $volid =~ m/vm-$vmid-state-/;
5610 next if $referenced->{$volid};
5611 my $path = $volid_hash->{$volid}->{path
};
5612 next if !$path; # just to be sure
5613 next if $referencedpath->{$path};
5615 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5616 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5623 my ($vmid, $nolock) = @_;
5625 my $cfg = PVE
::Storage
::config
();
5627 my $volid_hash = scan_volids
($cfg, $vmid);
5629 my $updatefn = sub {
5632 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5634 PVE
::QemuConfig-
>check_lock($conf);
5637 foreach my $volid (keys %$volid_hash) {
5638 my $info = $volid_hash->{$volid};
5639 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5642 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5644 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5647 if (defined($vmid)) {
5651 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5654 my $vmlist = config_list
();
5655 foreach my $vmid (keys %$vmlist) {
5659 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5665 sub restore_vma_archive
{
5666 my ($archive, $vmid, $user, $opts, $comp) = @_;
5668 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5669 my $readfrom = $archive;
5674 my $qarchive = PVE
::Tools
::shellquote
($archive);
5675 if ($comp eq 'gzip') {
5676 $uncomp = "zcat $qarchive|";
5677 } elsif ($comp eq 'lzop') {
5678 $uncomp = "lzop -d -c $qarchive|";
5680 die "unknown compression method '$comp'\n";
5685 my $tmpdir = "/var/tmp/vzdumptmp$$";
5688 # disable interrupts (always do cleanups)
5692 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5694 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5695 POSIX
::mkfifo
($mapfifo, 0600);
5698 my $openfifo = sub {
5699 open($fifofh, '>', $mapfifo) || die $!;
5702 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5709 my $rpcenv = PVE
::RPCEnvironment
::get
();
5711 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5712 my $tmpfn = "$conffile.$$.tmp";
5714 # Note: $oldconf is undef if VM does not exists
5715 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5716 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5718 my $print_devmap = sub {
5719 my $virtdev_hash = {};
5721 my $cfgfn = "$tmpdir/qemu-server.conf";
5723 # we can read the config - that is already extracted
5724 my $fh = IO
::File-
>new($cfgfn, "r") ||
5725 "unable to read qemu-server.conf - $!\n";
5727 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5729 my $pve_firewall_dir = '/etc/pve/firewall';
5730 mkdir $pve_firewall_dir; # make sure the dir exists
5731 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5734 while (defined(my $line = <$fh>)) {
5735 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5736 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5737 die "archive does not contain data for drive '$virtdev'\n"
5738 if !$devinfo->{$devname};
5739 if (defined($opts->{storage
})) {
5740 $storeid = $opts->{storage
} || 'local';
5741 } elsif (!$storeid) {
5744 $format = 'raw' if !$format;
5745 $devinfo->{$devname}->{devname
} = $devname;
5746 $devinfo->{$devname}->{virtdev
} = $virtdev;
5747 $devinfo->{$devname}->{format
} = $format;
5748 $devinfo->{$devname}->{storeid
} = $storeid;
5750 # check permission on storage
5751 my $pool = $opts->{pool
}; # todo: do we need that?
5752 if ($user ne 'root@pam') {
5753 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5756 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5760 foreach my $devname (keys %$devinfo) {
5761 die "found no device mapping information for device '$devname'\n"
5762 if !$devinfo->{$devname}->{virtdev
};
5765 my $cfg = PVE
::Storage
::config
();
5767 # create empty/temp config
5769 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5770 foreach_drive
($oldconf, sub {
5771 my ($ds, $drive) = @_;
5773 return if drive_is_cdrom
($drive);
5775 my $volid = $drive->{file
};
5777 return if !$volid || $volid =~ m
|^/|;
5779 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5780 return if !$path || !$owner || ($owner != $vmid);
5782 # Note: only delete disk we want to restore
5783 # other volumes will become unused
5784 if ($virtdev_hash->{$ds}) {
5785 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5792 # delete vmstate files
5793 # since after the restore we have no snapshots anymore
5794 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5795 my $snap = $oldconf->{snapshots
}->{$snapname};
5796 if ($snap->{vmstate
}) {
5797 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5806 foreach my $virtdev (sort keys %$virtdev_hash) {
5807 my $d = $virtdev_hash->{$virtdev};
5808 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5809 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5811 # test if requested format is supported
5812 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5813 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5814 $d->{format
} = $defFormat if !$supported;
5816 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5817 $d->{format
}, undef, $alloc_size);
5818 print STDERR
"new volume ID is '$volid'\n";
5819 $d->{volid
} = $volid;
5820 my $path = PVE
::Storage
::path
($cfg, $volid);
5822 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5824 my $write_zeros = 1;
5825 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5829 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5831 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5832 $map->{$virtdev} = $volid;
5835 $fh->seek(0, 0) || die "seek failed - $!\n";
5837 my $outfd = new IO
::File
($tmpfn, "w") ||
5838 die "unable to write config for VM $vmid\n";
5840 my $cookie = { netcount
=> 0 };
5841 while (defined(my $line = <$fh>)) {
5842 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5855 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5856 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5858 $oldtimeout = alarm($timeout);
5865 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5866 my ($dev_id, $size, $devname) = ($1, $2, $3);
5867 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5868 } elsif ($line =~ m/^CTIME: /) {
5869 # we correctly received the vma config, so we can disable
5870 # the timeout now for disk allocation (set to 10 minutes, so
5871 # that we always timeout if something goes wrong)
5874 print $fifofh "done\n";
5875 my $tmp = $oldtimeout || 0;
5876 $oldtimeout = undef;
5882 print "restore vma archive: $cmd\n";
5883 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5887 alarm($oldtimeout) if $oldtimeout;
5890 foreach my $devname (keys %$devinfo) {
5891 my $volid = $devinfo->{$devname}->{volid
};
5892 push @$vollist, $volid if $volid;
5895 my $cfg = PVE
::Storage
::config
();
5896 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5904 foreach my $devname (keys %$devinfo) {
5905 my $volid = $devinfo->{$devname}->{volid
};
5908 if ($volid =~ m
|^/|) {
5909 unlink $volid || die 'unlink failed\n';
5911 PVE
::Storage
::vdisk_free
($cfg, $volid);
5913 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5915 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5922 rename($tmpfn, $conffile) ||
5923 die "unable to commit configuration file '$conffile'\n";
5925 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5927 eval { rescan
($vmid, 1); };
5931 sub restore_tar_archive
{
5932 my ($archive, $vmid, $user, $opts) = @_;
5934 if ($archive ne '-') {
5935 my $firstfile = tar_archive_read_firstfile
($archive);
5936 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5937 if $firstfile ne 'qemu-server.conf';
5940 my $storecfg = PVE
::Storage
::config
();
5942 # destroy existing data - keep empty config
5943 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5944 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5946 my $tocmd = "/usr/lib/qemu-server/qmextract";
5948 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5949 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5950 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5951 $tocmd .= ' --info' if $opts->{info
};
5953 # tar option "xf" does not autodetect compression when read from STDIN,
5954 # so we pipe to zcat
5955 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5956 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5958 my $tmpdir = "/var/tmp/vzdumptmp$$";
5961 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5962 local $ENV{VZDUMP_VMID
} = $vmid;
5963 local $ENV{VZDUMP_USER
} = $user;
5965 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5966 my $tmpfn = "$conffile.$$.tmp";
5968 # disable interrupts (always do cleanups)
5972 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
5980 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5982 if ($archive eq '-') {
5983 print "extracting archive from STDIN\n";
5984 run_command
($cmd, input
=> "<&STDIN");
5986 print "extracting archive '$archive'\n";
5990 return if $opts->{info
};
5994 my $statfile = "$tmpdir/qmrestore.stat";
5995 if (my $fd = IO
::File-
>new($statfile, "r")) {
5996 while (defined (my $line = <$fd>)) {
5997 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5998 $map->{$1} = $2 if $1;
6000 print STDERR
"unable to parse line in statfile - $line\n";
6006 my $confsrc = "$tmpdir/qemu-server.conf";
6008 my $srcfd = new IO
::File
($confsrc, "r") ||
6009 die "unable to open file '$confsrc'\n";
6011 my $outfd = new IO
::File
($tmpfn, "w") ||
6012 die "unable to write config for VM $vmid\n";
6014 my $cookie = { netcount
=> 0 };
6015 while (defined (my $line = <$srcfd>)) {
6016 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6028 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6035 rename $tmpfn, $conffile ||
6036 die "unable to commit configuration file '$conffile'\n";
6038 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6040 eval { rescan
($vmid, 1); };
6044 sub foreach_storage_used_by_vm
{
6045 my ($conf, $func) = @_;
6049 foreach_drive
($conf, sub {
6050 my ($ds, $drive) = @_;
6051 return if drive_is_cdrom
($drive);
6053 my $volid = $drive->{file
};
6055 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6056 $sidhash->{$sid} = $sid if $sid;
6059 foreach my $sid (sort keys %$sidhash) {
6064 sub do_snapshots_with_qemu
{
6065 my ($storecfg, $volid) = @_;
6067 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6069 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6070 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6074 if ($volid =~ m/\.(qcow2|qed)$/){
6081 sub qga_check_running
{
6084 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6086 warn "Qemu Guest Agent is not running - $@";
6092 sub template_create
{
6093 my ($vmid, $conf, $disk) = @_;
6095 my $storecfg = PVE
::Storage
::config
();
6097 foreach_drive
($conf, sub {
6098 my ($ds, $drive) = @_;
6100 return if drive_is_cdrom
($drive);
6101 return if $disk && $ds ne $disk;
6103 my $volid = $drive->{file
};
6104 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6106 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6107 $drive->{file
} = $voliddst;
6108 $conf->{$ds} = print_drive
($vmid, $drive);
6109 PVE
::QemuConfig-
>write_config($vmid, $conf);
6113 sub qemu_img_convert
{
6114 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6116 my $storecfg = PVE
::Storage
::config
();
6117 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6118 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6120 if ($src_storeid && $dst_storeid) {
6122 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6124 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6125 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6127 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6128 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6130 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6131 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6134 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6135 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6136 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6137 if ($is_zero_initialized) {
6138 push @$cmd, "zeroinit:$dst_path";
6140 push @$cmd, $dst_path;
6145 if($line =~ m/\((\S+)\/100\
%\)/){
6147 my $transferred = int($size * $percent / 100);
6148 my $remaining = $size - $transferred;
6150 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6155 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6157 die "copy failed: $err" if $err;
6161 sub qemu_img_format
{
6162 my ($scfg, $volname) = @_;
6164 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6171 sub qemu_drive_mirror
{
6172 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6174 $jobs = {} if !$jobs;
6178 $jobs->{"drive-$drive"} = {};
6180 if ($dst_volid =~ /^nbd:/) {
6181 $qemu_target = $dst_volid;
6184 my $storecfg = PVE
::Storage
::config
();
6185 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6187 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6189 $format = qemu_img_format
($dst_scfg, $dst_volname);
6191 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6193 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6196 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6197 $opts->{format
} = $format if $format;
6199 print "drive mirror is starting for drive-$drive\n";
6201 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6204 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6205 die "mirroring error: $err";
6208 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6211 sub qemu_drive_mirror_monitor
{
6212 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6215 my $err_complete = 0;
6218 die "storage migration timed out\n" if $err_complete > 300;
6220 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6222 my $running_mirror_jobs = {};
6223 foreach my $stat (@$stats) {
6224 next if $stat->{type
} ne 'mirror';
6225 $running_mirror_jobs->{$stat->{device
}} = $stat;
6228 my $readycounter = 0;
6230 foreach my $job (keys %$jobs) {
6232 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6233 print "$job : finished\n";
6234 delete $jobs->{$job};
6238 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6240 my $busy = $running_mirror_jobs->{$job}->{busy
};
6241 my $ready = $running_mirror_jobs->{$job}->{ready
};
6242 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6243 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6244 my $remaining = $total - $transferred;
6245 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6247 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6250 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6253 last if scalar(keys %$jobs) == 0;
6255 if ($readycounter == scalar(keys %$jobs)) {
6256 print "all mirroring jobs are ready \n";
6257 last if $skipcomplete; #do the complete later
6259 if ($vmiddst && $vmiddst != $vmid) {
6260 my $agent_running = $qga && qga_check_running
($vmid);
6261 if ($agent_running) {
6262 print "freeze filesystem\n";
6263 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6265 print "suspend vm\n";
6266 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6269 # if we clone a disk for a new target vm, we don't switch the disk
6270 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6272 if ($agent_running) {
6273 print "unfreeze filesystem\n";
6274 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6276 print "resume vm\n";
6277 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6283 foreach my $job (keys %$jobs) {
6284 # try to switch the disk if source and destination are on the same guest
6285 print "$job: Completing block job...\n";
6287 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6288 if ($@ =~ m/cannot be completed/) {
6289 print "$job: Block job cannot be completed, try again.\n";
6292 print "$job: Completed successfully.\n";
6293 $jobs->{$job}->{complete
} = 1;
6304 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6305 die "mirroring error: $err";
6310 sub qemu_blockjobs_cancel
{
6311 my ($vmid, $jobs) = @_;
6313 foreach my $job (keys %$jobs) {
6314 print "$job: Cancelling block job\n";
6315 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6316 $jobs->{$job}->{cancel
} = 1;
6320 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6322 my $running_jobs = {};
6323 foreach my $stat (@$stats) {
6324 $running_jobs->{$stat->{device
}} = $stat;
6327 foreach my $job (keys %$jobs) {
6329 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6330 print "$job: Done.\n";
6331 delete $jobs->{$job};
6335 last if scalar(keys %$jobs) == 0;
6342 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6343 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6348 print "create linked clone of drive $drivename ($drive->{file})\n";
6349 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6350 push @$newvollist, $newvolid;
6353 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6354 $storeid = $storage if $storage;
6356 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6357 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6359 print "create full clone of drive $drivename ($drive->{file})\n";
6360 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, undef, ($size/1024));
6361 push @$newvollist, $newvolid;
6363 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6365 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6366 if (!$running || $snapname) {
6367 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6370 my $kvmver = get_running_qemu_version
($vmid);
6371 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6372 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6373 if $drive->{iothread
};
6376 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6380 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6383 $disk->{format
} = undef;
6384 $disk->{file
} = $newvolid;
6385 $disk->{size
} = $size;
6390 # this only works if VM is running
6391 sub get_current_qemu_machine
{
6394 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6395 my $res = vm_qmp_command
($vmid, $cmd);
6397 my ($current, $default);
6398 foreach my $e (@$res) {
6399 $default = $e->{name
} if $e->{'is-default'};
6400 $current = $e->{name
} if $e->{'is-current'};
6403 # fallback to the default machine if current is not supported by qemu
6404 return $current || $default || 'pc';
6407 sub get_running_qemu_version
{
6409 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6410 my $res = vm_qmp_command
($vmid, $cmd);
6411 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6414 sub qemu_machine_feature_enabled
{
6415 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6420 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6422 $current_major = $3;
6423 $current_minor = $4;
6425 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6427 $current_major = $1;
6428 $current_minor = $2;
6431 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6436 sub qemu_machine_pxe
{
6437 my ($vmid, $conf, $machine) = @_;
6439 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6441 foreach my $opt (keys %$conf) {
6442 next if $opt !~ m/^net(\d+)$/;
6443 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6445 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6446 return $machine.".pxe" if $romfile =~ m/pxe/;
6453 sub qemu_use_old_bios_files
{
6454 my ($machine_type) = @_;
6456 return if !$machine_type;
6458 my $use_old_bios_files = undef;
6460 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6462 $use_old_bios_files = 1;
6464 my $kvmver = kvm_user_version
();
6465 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6466 # load new efi bios files on migration. So this hack is required to allow
6467 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6468 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6469 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6472 return ($use_old_bios_files, $machine_type);
6475 sub create_efidisk
{
6476 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6478 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6480 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6481 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6482 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6484 my $path = PVE
::Storage
::path
($storecfg, $volid);
6486 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6488 die "Copying EFI vars image failed: $@" if $@;
6490 return ($volid, $vars_size);
6497 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6498 my (undef, $id, $function) = @_;
6499 my $res = { id
=> $id, function
=> $function};
6500 push @{$devices->{$id}}, $res;
6503 # Entries should be sorted by functions.
6504 foreach my $id (keys %$devices) {
6505 my $dev = $devices->{$id};
6506 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6512 sub vm_iothreads_list
{
6515 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6518 foreach my $iothread (@$res) {
6519 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6526 my ($conf, $drive) = @_;
6530 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6532 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6538 my $controller = int($drive->{index} / $maxdev);
6539 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6541 return ($maxdev, $controller, $controller_prefix);
6544 sub add_hyperv_enlightenments
{
6545 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6547 return if $winversion < 6;
6548 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6550 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6552 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6553 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6554 push @$cpuFlags , 'hv_vapic';
6555 push @$cpuFlags , 'hv_time';
6557 push @$cpuFlags , 'hv_spinlocks=0xffff';
6560 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6561 push @$cpuFlags , 'hv_reset';
6562 push @$cpuFlags , 'hv_vpindex';
6563 push @$cpuFlags , 'hv_runtime';
6566 if ($winversion >= 7) {
6567 push @$cpuFlags , 'hv_relaxed';
6571 sub windows_version
{
6574 return 0 if !$ostype;
6578 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6580 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6582 } elsif ($ostype =~ m/^win(\d+)$/) {
6589 sub resolve_dst_disk_format
{
6590 my ($storecfg, $storeid, $src_volname, $format) = @_;
6591 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6594 # if no target format is specified, use the source disk format as hint
6596 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6597 $format = qemu_img_format
($scfg, $src_volname);
6603 # test if requested format is supported - else use default
6604 my $supported = grep { $_ eq $format } @$validFormats;
6605 $format = $defFormat if !$supported;
6609 sub resolve_first_disk
{
6611 my @disks = PVE
::QemuServer
::valid_drive_names
();
6613 foreach my $ds (reverse @disks) {
6614 next if !$conf->{$ds};
6615 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6616 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6622 sub generate_smbios1_uuid
{
6623 my ($uuid, $uuid_str);
6624 UUID
::generate
($uuid);
6625 UUID
::unparse
($uuid, $uuid_str);
6626 return "uuid=$uuid_str";
6629 # bash completion helper
6631 sub complete_backup_archives
{
6632 my ($cmdname, $pname, $cvalue) = @_;
6634 my $cfg = PVE
::Storage
::config
();
6638 if ($cvalue =~ m/^([^:]+):/) {
6642 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6645 foreach my $id (keys %$data) {
6646 foreach my $item (@{$data->{$id}}) {
6647 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6648 push @$res, $item->{volid
} if defined($item->{volid
});
6655 my $complete_vmid_full = sub {
6658 my $idlist = vmstatus
();
6662 foreach my $id (keys %$idlist) {
6663 my $d = $idlist->{$id};
6664 if (defined($running)) {
6665 next if $d->{template
};
6666 next if $running && $d->{status
} ne 'running';
6667 next if !$running && $d->{status
} eq 'running';
6676 return &$complete_vmid_full();
6679 sub complete_vmid_stopped
{
6680 return &$complete_vmid_full(0);
6683 sub complete_vmid_running
{
6684 return &$complete_vmid_full(1);
6687 sub complete_storage
{
6689 my $cfg = PVE
::Storage
::config
();
6690 my $ids = $cfg->{ids
};
6693 foreach my $sid (keys %$ids) {
6694 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6695 next if !$ids->{$sid}->{content
}->{images
};