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 # Note about locking: we use flock on the config file protect
49 # against concurent actions.
50 # Aditionaly, we have a 'lock' setting in the config file. This
51 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
52 # allowed when such lock is set. But you can ignore this kind of
53 # lock with the --skiplock flag.
55 cfs_register_file
('/qemu-server/',
59 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
60 description
=> "Some command save/restore state from this location.",
66 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
67 description
=> "The name of the snapshot.",
68 type
=> 'string', format
=> 'pve-configid',
72 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
74 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
75 description
=> "The drive's backing file's data format.",
79 #no warnings 'redefine';
82 my ($controller, $vmid, $option, $value) = @_;
84 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
85 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
89 my $nodename = PVE
::INotify
::nodename
();
91 mkdir "/etc/pve/nodes/$nodename";
92 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
95 my $var_run_tmpdir = "/var/run/qemu-server";
96 mkdir $var_run_tmpdir;
98 my $lock_dir = "/var/lock/qemu-server";
101 my $pcisysfs = "/sys/bus/pci";
103 my $cpu_vendor_list = {
105 486 => 'GenuineIntel',
106 pentium
=> 'GenuineIntel',
107 pentium2
=> 'GenuineIntel',
108 pentium3
=> 'GenuineIntel',
109 coreduo
=> 'GenuineIntel',
110 core2duo
=> 'GenuineIntel',
111 Conroe
=> 'GenuineIntel',
112 Penryn
=> 'GenuineIntel',
113 Nehalem
=> 'GenuineIntel',
114 'Nehalem-IBRS' => 'GenuineIntel',
115 Westmere
=> 'GenuineIntel',
116 'Westmere-IBRS' => 'GenuineIntel',
117 SandyBridge
=> 'GenuineIntel',
118 'SandyBridge-IBRS' => 'GenuineIntel',
119 IvyBridge
=> 'GenuineIntel',
120 'IvyBridge-IBRS' => 'GenuineIntel',
121 Haswell
=> 'GenuineIntel',
122 'Haswell-IBRS' => 'GenuineIntel',
123 'Haswell-noTSX' => 'GenuineIntel',
124 'Haswell-noTSX-IBRS' => 'GenuineIntel',
125 Broadwell
=> 'GenuineIntel',
126 'Broadwell-IBRS' => 'GenuineIntel',
127 'Broadwell-noTSX' => 'GenuineIntel',
128 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
129 'Skylake-Client' => 'GenuineIntel',
130 'Skylake-Client-IBRS' => 'GenuineIntel',
131 'Skylake-Server' => 'GenuineIntel',
132 'Skylake-Server-IBRS' => 'GenuineIntel',
135 athlon
=> 'AuthenticAMD',
136 phenom
=> 'AuthenticAMD',
137 Opteron_G1
=> 'AuthenticAMD',
138 Opteron_G2
=> 'AuthenticAMD',
139 Opteron_G3
=> 'AuthenticAMD',
140 Opteron_G4
=> 'AuthenticAMD',
141 Opteron_G5
=> 'AuthenticAMD',
142 EPYC
=> 'AuthenticAMD',
143 'EPYC-IBPB' => 'AuthenticAMD',
145 # generic types, use vendor from host node
154 my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
158 description
=> "Emulated CPU type.",
160 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
165 description
=> "Do not identify as a KVM virtual machine.",
171 description
=> "List of additional CPU flags separated by ';'."
172 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
173 . " Currently supported flags: 'pcid', 'spec-ctrl'.",
174 format_description
=> '+FLAG[;-FLAG...]',
176 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
185 enum
=> [qw(i6300esb ib700)],
186 description
=> "Watchdog type to emulate.",
187 default => 'i6300esb',
192 enum
=> [qw(reset shutdown poweroff pause debug none)],
193 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
197 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
203 description
=> "Specifies whether a VM will be started during system bootup.",
209 description
=> "Automatic restart after crash (currently ignored).",
214 type
=> 'string', format
=> 'pve-hotplug-features',
215 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'.",
216 default => 'network,disk,usb',
221 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
227 description
=> "Lock/unlock the VM.",
228 enum
=> [qw(migrate backup snapshot rollback)],
233 description
=> "Limit of CPU usage.",
234 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.",
242 description
=> "CPU weight for a VM.",
243 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.",
251 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
258 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
264 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",
272 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.".
273 "It should not be necessary to set it.",
274 enum
=> PVE
::Tools
::kvmkeymaplist
(),
279 type
=> 'string', format
=> 'dns-name',
280 description
=> "Set a name for the VM. Only used on the configuration web interface.",
285 description
=> "SCSI controller model",
286 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
292 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
297 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
298 description
=> "Specify guest operating system.",
299 verbose_description
=> <<EODESC,
300 Specify guest operating system. This is used to enable special
301 optimization/features for specific operating systems:
304 other;; unspecified OS
305 wxp;; Microsoft Windows XP
306 w2k;; Microsoft Windows 2000
307 w2k3;; Microsoft Windows 2003
308 w2k8;; Microsoft Windows 2008
309 wvista;; Microsoft Windows Vista
310 win7;; Microsoft Windows 7
311 win8;; Microsoft Windows 8/2012/2012r2
312 win10;; Microsoft Windows 10/2016
313 l24;; Linux 2.4 Kernel
314 l26;; Linux 2.6/3.X Kernel
315 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
321 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
322 pattern
=> '[acdn]{1,4}',
327 type
=> 'string', format
=> 'pve-qm-bootdisk',
328 description
=> "Enable booting from specified disk.",
329 pattern
=> '(ide|sata|scsi|virtio)\d+',
334 description
=> "The number of CPUs. Please use option -sockets instead.",
341 description
=> "The number of CPU sockets.",
348 description
=> "The number of cores per socket.",
355 description
=> "Enable/disable NUMA.",
361 description
=> "Enable/disable hugepages memory.",
362 enum
=> [qw(any 2 1024)],
367 description
=> "Number of hotplugged vcpus.",
374 description
=> "Enable/disable ACPI.",
380 description
=> "Enable/disable Qemu GuestAgent.",
386 description
=> "Enable/disable KVM hardware virtualization.",
392 description
=> "Enable/disable time drift fix.",
398 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
403 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
408 description
=> "Select the VGA type.",
409 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
410 " modes (>= 1280x1024x16) then you should use the options " .
411 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
412 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
413 "display sever. For win* OS you can select how many independent " .
414 "displays you want, Linux guests can add displays them self. " .
415 "You can also run without any graphic card, using a serial device" .
417 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
421 type
=> 'string', format
=> 'pve-qm-watchdog',
422 description
=> "Create a virtual hardware watchdog device.",
423 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
424 " (by a guest action), the watchdog must be periodically polled " .
425 "by an agent inside the guest or else the watchdog will reset " .
426 "the guest (or execute the respective action specified)",
431 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
432 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'.",
433 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
436 startup
=> get_standard_option
('pve-startup-order'),
440 description
=> "Enable/disable Template.",
446 description
=> "Arbitrary arguments passed to kvm.",
447 verbose_description
=> <<EODESCR,
448 Arbitrary arguments passed to kvm, for example:
450 args: -no-reboot -no-hpet
452 NOTE: this option is for experts only.
459 description
=> "Enable/disable the USB tablet device.",
460 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
461 "usually needed to allow absolute mouse positioning with VNC. " .
462 "Else the mouse runs out of sync with normal VNC clients. " .
463 "If you're running lots of console-only guests on one host, " .
464 "you may consider disabling this to save some context switches. " .
465 "This is turned off by default if you use spice (-vga=qxl).",
470 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
474 migrate_downtime
=> {
477 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
483 type
=> 'string', format
=> 'pve-qm-ide',
484 typetext
=> '<volume>',
485 description
=> "This is an alias for option -ide2",
489 description
=> "Emulated CPU type.",
493 parent
=> get_standard_option
('pve-snapshot-name', {
495 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
499 description
=> "Timestamp for snapshots.",
505 type
=> 'string', format
=> 'pve-volume-id',
506 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
508 vmstatestorage
=> get_standard_option
('pve-storage-id', {
509 description
=> "Default storage for VM state volumes/files.",
513 description
=> "Specific the Qemu machine type.",
515 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
520 description
=> "Specify SMBIOS type 1 fields.",
521 type
=> 'string', format
=> 'pve-qm-smbios1',
528 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
534 enum
=> [ qw(seabios ovmf) ],
535 description
=> "Select BIOS implementation.",
536 default => 'seabios',
541 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.",
545 type
=> 'string', format
=> 'address-list',
546 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.",
551 format
=> 'urlencoded',
552 description
=> "cloud-init : Setup public SSH keys (one key per line, " .
557 description
=> "cloud-init: Hostname to use instead of the vm-name + search-domain.",
558 type
=> 'string', format
=> 'dns-name',
563 # what about other qemu settings ?
565 #machine => 'string',
578 ##soundhw => 'string',
580 while (my ($k, $v) = each %$confdesc) {
581 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
584 my $MAX_IDE_DISKS = 4;
585 my $MAX_SCSI_DISKS = 14;
586 my $MAX_VIRTIO_DISKS = 16;
587 my $MAX_SATA_DISKS = 6;
588 my $MAX_USB_DEVICES = 5;
590 my $MAX_UNUSED_DISKS = 8;
591 my $MAX_HOSTPCI_DEVICES = 4;
592 my $MAX_SERIAL_PORTS = 4;
593 my $MAX_PARALLEL_PORTS = 3;
599 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
600 description
=> "CPUs accessing this NUMA node.",
601 format_description
=> "id[-id];...",
605 description
=> "Amount of memory this NUMA node provides.",
610 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
611 description
=> "Host NUMA nodes to use.",
612 format_description
=> "id[-id];...",
617 enum
=> [qw(preferred bind interleave)],
618 description
=> "NUMA allocation policy.",
622 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
625 type
=> 'string', format
=> $numa_fmt,
626 description
=> "NUMA topology.",
628 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
630 for (my $i = 0; $i < $MAX_NUMA; $i++) {
631 $confdesc->{"numa$i"} = $numadesc;
634 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
635 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
636 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
637 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
639 my $net_fmt_bridge_descr = <<__EOD__;
640 Bridge to attach the network device to. The Proxmox VE standard bridge
643 If you do not specify a bridge, we create a kvm user (NATed) network
644 device, which provides DHCP and DNS services. The following addresses
651 The DHCP server assign addresses to the guest starting from 10.0.2.15.
657 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
658 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
659 format_description
=> "XX:XX:XX:XX:XX:XX",
664 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'.",
665 enum
=> $nic_model_list,
668 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
671 description
=> $net_fmt_bridge_descr,
672 format_description
=> 'bridge',
677 minimum
=> 0, maximum
=> 16,
678 description
=> 'Number of packet queues to be used on the device.',
684 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
689 minimum
=> 1, maximum
=> 4094,
690 description
=> 'VLAN tag to apply to packets on this interface.',
695 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
696 description
=> 'VLAN trunks to pass through this interface.',
697 format_description
=> 'vlanid[;vlanid...]',
702 description
=> 'Whether this interface should be protected by the firewall.',
707 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
714 type
=> 'string', format
=> $net_fmt,
715 description
=> "Specify network devices.",
718 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
723 format
=> 'pve-ipv4-config',
724 format_description
=> 'IPv4Format/CIDR',
725 description
=> 'IPv4 address in CIDR format.',
732 format_description
=> 'GatewayIPv4',
733 description
=> 'Default gateway for IPv4 traffic.',
739 format
=> 'pve-ipv6-config',
740 format_description
=> 'IPv6Format/CIDR',
741 description
=> 'IPv6 address in CIDR format.',
748 format_description
=> 'GatewayIPv6',
749 description
=> 'Default gateway for IPv6 traffic.',
754 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
757 type
=> 'string', format
=> 'pve-qm-ipconfig',
758 description
=> <<'EODESCR',
759 cloud-init: Specify IP addresses and gateways for the corresponding interface.
761 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
763 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
764 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
766 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
769 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
771 for (my $i = 0; $i < $MAX_NETS; $i++) {
772 $confdesc->{"net$i"} = $netdesc;
773 $confdesc->{"ipconfig$i"} = $ipconfigdesc;
776 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
777 sub verify_volume_id_or_qm_path
{
778 my ($volid, $noerr) = @_;
780 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
784 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
785 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
787 return undef if $noerr;
795 my %drivedesc_base = (
796 volume
=> { alias
=> 'file' },
799 format
=> 'pve-volume-id-or-qm-path',
801 format_description
=> 'volume',
802 description
=> "The drive's backing volume.",
806 enum
=> [qw(cdrom disk)],
807 description
=> "The drive's media type.",
813 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
818 description
=> "Force the drive's physical geometry to have a specific head count.",
823 description
=> "Force the drive's physical geometry to have a specific sector count.",
828 enum
=> [qw(none lba auto)],
829 description
=> "Force disk geometry bios translation mode.",
834 description
=> "Controls qemu's snapshot mode feature."
835 . " If activated, changes made to the disk are temporary and will"
836 . " be discarded when the VM is shutdown.",
841 enum
=> [qw(none writethrough writeback unsafe directsync)],
842 description
=> "The drive's cache mode",
845 format
=> get_standard_option
('pve-qm-image-format'),
848 format
=> 'disk-size',
849 format_description
=> 'DiskSize',
850 description
=> "Disk size. This is purely informational and has no effect.",
855 description
=> "Whether the drive should be included when making backups.",
860 description
=> 'Whether the drive should considered for replication jobs.',
866 enum
=> [qw(ignore report stop)],
867 description
=> 'Read error action.',
872 enum
=> [qw(enospc ignore report stop)],
873 description
=> 'Write error action.',
878 enum
=> [qw(native threads)],
879 description
=> 'AIO type to use.',
884 enum
=> [qw(ignore on)],
885 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
890 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
895 format
=> 'urlencoded',
896 format_description
=> 'serial',
897 maxLength
=> 20*3, # *3 since it's %xx url enoded
898 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
903 description
=> 'Mark this locally-managed volume as available on all nodes',
904 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!",
910 my %iothread_fmt = ( iothread
=> {
912 description
=> "Whether to use iothreads for this drive",
919 format
=> 'urlencoded',
920 format_description
=> 'model',
921 maxLength
=> 40*3, # *3 since it's %xx url enoded
922 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
930 description
=> "Number of queues.",
936 my %scsiblock_fmt = (
939 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",
945 my $add_throttle_desc = sub {
946 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
949 format_description
=> $unit,
950 description
=> "Maximum $what in $longunit.",
953 $d->{minimum
} = $minimum if defined($minimum);
954 $drivedesc_base{$key} = $d;
956 # throughput: (leaky bucket)
957 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
958 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
959 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
960 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
961 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
962 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
963 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
964 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
965 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
967 # pools: (pool of IO before throttling starts taking effect)
968 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
969 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
970 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
971 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
972 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
973 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
976 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
977 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
978 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
979 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
980 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
981 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
984 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
985 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
986 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
987 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
993 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
997 type
=> 'string', format
=> $ide_fmt,
998 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1000 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1010 type
=> 'string', format
=> $scsi_fmt,
1011 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1013 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1020 type
=> 'string', format
=> $sata_fmt,
1021 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1023 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1031 type
=> 'string', format
=> $virtio_fmt,
1032 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1034 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1036 my $alldrive_fmt = {
1045 volume
=> { alias
=> 'file' },
1048 format
=> 'pve-volume-id-or-qm-path',
1050 format_description
=> 'volume',
1051 description
=> "The drive's backing volume.",
1053 format
=> get_standard_option
('pve-qm-image-format'),
1056 format
=> 'disk-size',
1057 format_description
=> 'DiskSize',
1058 description
=> "Disk size. This is purely informational and has no effect.",
1063 my $efidisk_desc = {
1065 type
=> 'string', format
=> $efidisk_fmt,
1066 description
=> "Configure a Disk for storing EFI vars",
1069 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1074 type
=> 'string', format
=> 'pve-qm-usb-device',
1075 format_description
=> 'HOSTUSBDEVICE|spice',
1076 description
=> <<EODESCR,
1077 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1079 'bus-port(.port)*' (decimal numbers) or
1080 'vendor_id:product_id' (hexadeciaml numbers) or
1083 You can use the 'lsusb -t' command to list existing usb devices.
1085 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1087 The value 'spice' can be used to add a usb redirection devices for spice.
1093 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).",
1100 type
=> 'string', format
=> $usb_fmt,
1101 description
=> "Configure an USB device (n is 0 to 4).",
1103 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1105 # NOTE: the match-groups of this regex are used in parse_hostpci
1106 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1111 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1112 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1113 description
=> <<EODESCR,
1114 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1115 of PCI virtual functions of the host. HOSTPCIID syntax is:
1117 'bus:dev.func' (hexadecimal numbers)
1119 You can us the 'lspci' command to list existing PCI devices.
1124 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1130 pattern
=> '[^,;]+',
1131 format_description
=> 'string',
1132 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1137 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1143 description
=> "Enable vfio-vga device support.",
1148 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1152 type
=> 'string', format
=> 'pve-qm-hostpci',
1153 description
=> "Map host PCI devices into guest.",
1154 verbose_description
=> <<EODESCR,
1155 Map host PCI devices into guest.
1157 NOTE: This option allows direct access to host hardware. So it is no longer
1158 possible to migrate such machines - use with special care.
1160 CAUTION: Experimental! User reported problems with this option.
1163 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1168 pattern
=> '(/dev/.+|socket)',
1169 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1170 verbose_description
=> <<EODESCR,
1171 Create a serial device inside the VM (n is 0 to 3), and pass through a
1172 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1173 host side (use 'qm terminal' to open a terminal connection).
1175 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1177 CAUTION: Experimental! User reported problems with this option.
1184 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1185 description
=> "Map host parallel devices (n is 0 to 2).",
1186 verbose_description
=> <<EODESCR,
1187 Map host parallel devices (n is 0 to 2).
1189 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1191 CAUTION: Experimental! User reported problems with this option.
1195 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1196 $confdesc->{"parallel$i"} = $paralleldesc;
1199 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1200 $confdesc->{"serial$i"} = $serialdesc;
1203 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1204 $confdesc->{"hostpci$i"} = $hostpcidesc;
1207 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1208 $drivename_hash->{"ide$i"} = 1;
1209 $confdesc->{"ide$i"} = $idedesc;
1212 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1213 $drivename_hash->{"sata$i"} = 1;
1214 $confdesc->{"sata$i"} = $satadesc;
1217 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1218 $drivename_hash->{"scsi$i"} = 1;
1219 $confdesc->{"scsi$i"} = $scsidesc ;
1222 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1223 $drivename_hash->{"virtio$i"} = 1;
1224 $confdesc->{"virtio$i"} = $virtiodesc;
1227 $drivename_hash->{efidisk0
} = 1;
1228 $confdesc->{efidisk0
} = $efidisk_desc;
1230 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1231 $confdesc->{"usb$i"} = $usbdesc;
1236 type
=> 'string', format
=> 'pve-volume-id',
1237 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1240 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1241 $confdesc->{"unused$i"} = $unuseddesc;
1244 my $kvm_api_version = 0;
1248 return $kvm_api_version if $kvm_api_version;
1250 my $fh = IO
::File-
>new("</dev/kvm") ||
1253 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1254 $kvm_api_version = $v;
1259 return $kvm_api_version;
1262 my $kvm_user_version;
1264 sub kvm_user_version
{
1266 return $kvm_user_version if $kvm_user_version;
1268 $kvm_user_version = 'unknown';
1272 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1273 $kvm_user_version = $2;
1277 eval { run_command
("kvm -version", outfunc
=> $code); };
1280 return $kvm_user_version;
1284 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1286 sub valid_drive_names
{
1287 # order is important - used to autoselect boot disk
1288 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1289 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1290 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1291 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1295 sub is_valid_drivename
{
1298 return defined($drivename_hash->{$dev});
1303 return defined($confdesc->{$key});
1307 return $nic_model_list;
1310 sub os_list_description
{
1314 wxp
=> 'Windows XP',
1315 w2k
=> 'Windows 2000',
1316 w2k3
=>, 'Windows 2003',
1317 w2k8
=> 'Windows 2008',
1318 wvista
=> 'Windows Vista',
1319 win7
=> 'Windows 7',
1320 win8
=> 'Windows 8/2012',
1321 win10
=> 'Windows 10/2016',
1329 sub get_cdrom_path
{
1331 return $cdrom_path if $cdrom_path;
1333 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1334 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1335 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1339 my ($storecfg, $vmid, $cdrom) = @_;
1341 if ($cdrom eq 'cdrom') {
1342 return get_cdrom_path
();
1343 } elsif ($cdrom eq 'none') {
1345 } elsif ($cdrom =~ m
|^/|) {
1348 return PVE
::Storage
::path
($storecfg, $cdrom);
1352 # try to convert old style file names to volume IDs
1353 sub filename_to_volume_id
{
1354 my ($vmid, $file, $media) = @_;
1356 if (!($file eq 'none' || $file eq 'cdrom' ||
1357 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1359 return undef if $file =~ m
|/|;
1361 if ($media && $media eq 'cdrom') {
1362 $file = "local:iso/$file";
1364 $file = "local:$vmid/$file";
1371 sub verify_media_type
{
1372 my ($opt, $vtype, $media) = @_;
1377 if ($media eq 'disk') {
1379 } elsif ($media eq 'cdrom') {
1382 die "internal error";
1385 return if ($vtype eq $etype);
1387 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1390 sub cleanup_drive_path
{
1391 my ($opt, $storecfg, $drive) = @_;
1393 # try to convert filesystem paths to volume IDs
1395 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1396 ($drive->{file
} !~ m
|^/dev/.+|) &&
1397 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1398 ($drive->{file
} !~ m/^\d+$/)) {
1399 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1400 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1401 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1402 verify_media_type
($opt, $vtype, $drive->{media
});
1403 $drive->{file
} = $volid;
1406 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1409 sub parse_hotplug_features
{
1414 return $res if $data eq '0';
1416 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1418 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1419 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1422 die "invalid hotplug feature '$feature'\n";
1428 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1429 sub pve_verify_hotplug_features
{
1430 my ($value, $noerr) = @_;
1432 return $value if parse_hotplug_features
($value);
1434 return undef if $noerr;
1436 die "unable to parse hotplug option\n";
1439 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1440 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1441 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1442 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1443 # [,iothread=on][,serial=serial][,model=model]
1446 my ($key, $data) = @_;
1448 my ($interface, $index);
1450 if ($key =~ m/^([^\d]+)(\d+)$/) {
1457 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1458 : $confdesc->{$key}->{format
};
1460 warn "invalid drive key: $key\n";
1463 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1464 return undef if !$res;
1465 $res->{interface
} = $interface;
1466 $res->{index} = $index;
1469 foreach my $opt (qw(bps bps_rd bps_wr)) {
1470 if (my $bps = defined(delete $res->{$opt})) {
1471 if (defined($res->{"m$opt"})) {
1472 warn "both $opt and m$opt specified\n";
1476 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1480 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1481 for my $requirement (
1482 [mbps_max
=> 'mbps'],
1483 [mbps_rd_max
=> 'mbps_rd'],
1484 [mbps_wr_max
=> 'mbps_wr'],
1485 [miops_max
=> 'miops'],
1486 [miops_rd_max
=> 'miops_rd'],
1487 [miops_wr_max
=> 'miops_wr'],
1488 [bps_max_length
=> 'mbps_max'],
1489 [bps_rd_max_length
=> 'mbps_rd_max'],
1490 [bps_wr_max_length
=> 'mbps_wr_max'],
1491 [iops_max_length
=> 'iops_max'],
1492 [iops_rd_max_length
=> 'iops_rd_max'],
1493 [iops_wr_max_length
=> 'iops_wr_max']) {
1494 my ($option, $requires) = @$requirement;
1495 if ($res->{$option} && !$res->{$requires}) {
1496 warn "$option requires $requires\n";
1501 return undef if $error;
1503 return undef if $res->{mbps_rd
} && $res->{mbps
};
1504 return undef if $res->{mbps_wr
} && $res->{mbps
};
1505 return undef if $res->{iops_rd
} && $res->{iops
};
1506 return undef if $res->{iops_wr
} && $res->{iops
};
1508 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1509 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1510 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1511 return undef if $res->{interface
} eq 'virtio';
1514 if (my $size = $res->{size
}) {
1515 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1522 my ($vmid, $drive) = @_;
1523 my $data = { %$drive };
1524 delete $data->{$_} for qw(index interface);
1525 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1529 my($fh, $noerr) = @_;
1532 my $SG_GET_VERSION_NUM = 0x2282;
1534 my $versionbuf = "\x00" x
8;
1535 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1537 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1540 my $version = unpack("I", $versionbuf);
1541 if ($version < 30000) {
1542 die "scsi generic interface too old\n" if !$noerr;
1546 my $buf = "\x00" x
36;
1547 my $sensebuf = "\x00" x
8;
1548 my $cmd = pack("C x3 C x1", 0x12, 36);
1550 # see /usr/include/scsi/sg.h
1551 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";
1553 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1554 length($sensebuf), 0, length($buf), $buf,
1555 $cmd, $sensebuf, 6000);
1557 $ret = ioctl($fh, $SG_IO, $packet);
1559 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1563 my @res = unpack($sg_io_hdr_t, $packet);
1564 if ($res[17] || $res[18]) {
1565 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1570 (my $byte0, my $byte1, $res->{vendor
},
1571 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1573 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1574 $res->{type
} = $byte0 & 31;
1582 my $fh = IO
::File-
>new("+<$path") || return undef;
1583 my $res = scsi_inquiry
($fh, 1);
1589 sub machine_type_is_q35
{
1592 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1595 sub print_tabletdevice_full
{
1598 my $q35 = machine_type_is_q35
($conf);
1600 # we use uhci for old VMs because tablet driver was buggy in older qemu
1601 my $usbbus = $q35 ?
"ehci" : "uhci";
1603 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1606 sub print_drivedevice_full
{
1607 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1612 if ($drive->{interface
} eq 'virtio') {
1613 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1614 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1615 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1616 } elsif ($drive->{interface
} eq 'scsi') {
1618 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1619 my $unit = $drive->{index} % $maxdev;
1620 my $devicetype = 'hd';
1622 if (drive_is_cdrom
($drive)) {
1625 if ($drive->{file
} =~ m
|^/|) {
1626 $path = $drive->{file
};
1627 if (my $info = path_is_scsi
($path)) {
1628 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1629 $devicetype = 'block';
1630 } elsif ($info->{type
} == 1) { # tape
1631 $devicetype = 'generic';
1635 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1638 if($path =~ m/^iscsi\:\/\
//){
1639 $devicetype = 'generic';
1643 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1644 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1646 $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}";
1649 } elsif ($drive->{interface
} eq 'ide'){
1651 my $controller = int($drive->{index} / $maxdev);
1652 my $unit = $drive->{index} % $maxdev;
1653 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1655 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1656 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1657 $model = URI
::Escape
::uri_unescape
($model);
1658 $device .= ",model=$model";
1660 } elsif ($drive->{interface
} eq 'sata'){
1661 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1662 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1663 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1664 } elsif ($drive->{interface
} eq 'usb') {
1666 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1668 die "unsupported interface type";
1671 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1676 sub get_initiator_name
{
1679 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1680 while (defined(my $line = <$fh>)) {
1681 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1690 sub print_drive_full
{
1691 my ($storecfg, $vmid, $drive) = @_;
1694 my $volid = $drive->{file
};
1697 if (drive_is_cdrom
($drive)) {
1698 $path = get_iso_path
($storecfg, $vmid, $volid);
1700 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1702 $path = PVE
::Storage
::path
($storecfg, $volid);
1703 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1704 $format = qemu_img_format
($scfg, $volname);
1712 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1713 foreach my $o (@qemu_drive_options) {
1714 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1717 # snapshot only accepts on|off
1718 if (defined($drive->{snapshot
})) {
1719 my $v = $drive->{snapshot
} ?
'on' : 'off';
1720 $opts .= ",snapshot=$v";
1723 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1724 my ($dir, $qmpname) = @$type;
1725 if (my $v = $drive->{"mbps$dir"}) {
1726 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1728 if (my $v = $drive->{"mbps${dir}_max"}) {
1729 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1731 if (my $v = $drive->{"bps${dir}_max_length"}) {
1732 $opts .= ",throttling.bps$qmpname-max-length=$v";
1734 if (my $v = $drive->{"iops${dir}"}) {
1735 $opts .= ",throttling.iops$qmpname=$v";
1737 if (my $v = $drive->{"iops${dir}_max"}) {
1738 $opts .= ",throttling.iops$qmpname-max=$v";
1740 if (my $v = $drive->{"iops${dir}_max_length"}) {
1741 $opts .= ",throttling.iops$qmpname-max-length=$v";
1745 if (my $serial = $drive->{serial
}) {
1746 $serial = URI
::Escape
::uri_unescape
($serial);
1747 $opts .= ",serial=$serial";
1750 $opts .= ",format=$format" if $format && !$drive->{format
};
1752 my $cache_direct = 0;
1754 if (my $cache = $drive->{cache
}) {
1755 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1756 } elsif (!drive_is_cdrom
($drive)) {
1757 $opts .= ",cache=none";
1761 # aio native works only with O_DIRECT
1762 if (!$drive->{aio
}) {
1764 $opts .= ",aio=native";
1766 $opts .= ",aio=threads";
1770 if (!drive_is_cdrom
($drive)) {
1772 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1773 $detectzeroes = 'off';
1774 } elsif ($drive->{discard
}) {
1775 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1777 # This used to be our default with discard not being specified:
1778 $detectzeroes = 'on';
1780 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1783 my $pathinfo = $path ?
"file=$path," : '';
1785 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1788 sub print_netdevice_full
{
1789 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1791 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1793 my $device = $net->{model
};
1794 if ($net->{model
} eq 'virtio') {
1795 $device = 'virtio-net-pci';
1798 my $pciaddr = print_pci_addr
("$netid", $bridges);
1799 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1800 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1801 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1802 my $vectors = $net->{queues
} * 2 + 2;
1803 $tmpstr .= ",vectors=$vectors,mq=on";
1805 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1807 if ($use_old_bios_files) {
1809 if ($device eq 'virtio-net-pci') {
1810 $romfile = 'pxe-virtio.rom';
1811 } elsif ($device eq 'e1000') {
1812 $romfile = 'pxe-e1000.rom';
1813 } elsif ($device eq 'ne2k') {
1814 $romfile = 'pxe-ne2k_pci.rom';
1815 } elsif ($device eq 'pcnet') {
1816 $romfile = 'pxe-pcnet.rom';
1817 } elsif ($device eq 'rtl8139') {
1818 $romfile = 'pxe-rtl8139.rom';
1820 $tmpstr .= ",romfile=$romfile" if $romfile;
1826 sub print_netdev_full
{
1827 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1830 if ($netid =~ m/^net(\d+)$/) {
1834 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1836 my $ifname = "tap${vmid}i$i";
1838 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1839 die "interface name '$ifname' is too long (max 15 character)\n"
1840 if length($ifname) >= 16;
1842 my $vhostparam = '';
1843 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1845 my $vmname = $conf->{name
} || "vm$vmid";
1848 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1850 if ($net->{bridge
}) {
1851 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1853 $netdev = "type=user,id=$netid,hostname=$vmname";
1856 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1862 sub print_cpu_device
{
1863 my ($conf, $id) = @_;
1865 my $kvm = $conf->{kvm
} // 1;
1866 my $cpu = $kvm ?
"kvm64" : "qemu64";
1867 if (my $cputype = $conf->{cpu
}) {
1868 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1869 or die "Cannot parse cpu description: $cputype\n";
1870 $cpu = $cpuconf->{cputype
};
1873 my $cores = $conf->{cores
} || 1;
1875 my $current_core = ($id - 1) % $cores;
1876 my $current_socket = int(($id - 1 - $current_core)/$cores);
1878 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1881 sub drive_is_cdrom
{
1884 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1888 sub parse_number_sets
{
1891 foreach my $part (split(/;/, $set)) {
1892 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1893 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1894 push @$res, [ $1, $2 ];
1896 die "invalid range: $part\n";
1905 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1906 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1907 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1914 return undef if !$value;
1916 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1918 my @idlist = split(/;/, $res->{host
});
1919 delete $res->{host
};
1920 foreach my $id (@idlist) {
1921 if ($id =~ /^$PCIRE$/) {
1923 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1925 my $pcidevices = lspci
($1);
1926 $res->{pciid
} = $pcidevices->{$1};
1929 # should have been caught by parse_property_string already
1930 die "failed to parse PCI id: $id\n";
1936 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1940 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1945 if (!defined($res->{macaddr
})) {
1946 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1947 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1949 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
() if !defined($res->{macaddr
});
1953 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1954 sub parse_ipconfig
{
1957 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1963 if ($res->{gw
} && !$res->{ip
}) {
1964 warn 'gateway specified without specifying an IP address';
1967 if ($res->{gw6
} && !$res->{ip6
}) {
1968 warn 'IPv6 gateway specified without specifying an IPv6 address';
1971 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1972 warn 'gateway specified together with DHCP';
1975 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1977 warn "IPv6 gateway specified together with $res->{ip6} address";
1981 if (!$res->{ip
} && !$res->{ip6
}) {
1982 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1991 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1994 sub add_random_macs
{
1995 my ($settings) = @_;
1997 foreach my $opt (keys %$settings) {
1998 next if $opt !~ m/^net(\d+)$/;
1999 my $net = parse_net
($settings->{$opt});
2001 $settings->{$opt} = print_net
($net);
2005 sub vm_is_volid_owner
{
2006 my ($storecfg, $vmid, $volid) = @_;
2008 if ($volid !~ m
|^/|) {
2010 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2011 if ($owner && ($owner == $vmid)) {
2019 sub split_flagged_list
{
2020 my $text = shift || '';
2021 $text =~ s/[,;]/ /g;
2023 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2026 sub join_flagged_list
{
2027 my ($how, $lst) = @_;
2028 join $how, map { $lst->{$_} . $_ } keys %$lst;
2031 sub vmconfig_delete_pending_option
{
2032 my ($conf, $key, $force) = @_;
2034 delete $conf->{pending
}->{$key};
2035 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2036 $pending_delete_hash->{$key} = $force ?
'!' : '';
2037 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2040 sub vmconfig_undelete_pending_option
{
2041 my ($conf, $key) = @_;
2043 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2044 delete $pending_delete_hash->{$key};
2046 if (%$pending_delete_hash) {
2047 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2049 delete $conf->{pending
}->{delete};
2053 sub vmconfig_register_unused_drive
{
2054 my ($storecfg, $vmid, $conf, $drive) = @_;
2056 if (!drive_is_cdrom
($drive)) {
2057 my $volid = $drive->{file
};
2058 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2059 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2064 sub vmconfig_cleanup_pending
{
2067 # remove pending changes when nothing changed
2069 foreach my $opt (keys %{$conf->{pending
}}) {
2070 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2072 delete $conf->{pending
}->{$opt};
2076 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2077 my $pending_delete_hash = {};
2078 while (my ($opt, $force) = each %$current_delete_hash) {
2079 if (defined($conf->{$opt})) {
2080 $pending_delete_hash->{$opt} = $force;
2086 if (%$pending_delete_hash) {
2087 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2089 delete $conf->{pending
}->{delete};
2095 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2099 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2100 format_description
=> 'UUID',
2101 description
=> "Set SMBIOS1 UUID.",
2107 format_description
=> 'string',
2108 description
=> "Set SMBIOS1 version.",
2114 format_description
=> 'string',
2115 description
=> "Set SMBIOS1 serial number.",
2121 format_description
=> 'string',
2122 description
=> "Set SMBIOS1 manufacturer.",
2128 format_description
=> 'string',
2129 description
=> "Set SMBIOS1 product ID.",
2135 format_description
=> 'string',
2136 description
=> "Set SMBIOS1 SKU string.",
2142 format_description
=> 'string',
2143 description
=> "Set SMBIOS1 family string.",
2151 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2158 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2161 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2163 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2164 sub verify_bootdisk
{
2165 my ($value, $noerr) = @_;
2167 return $value if is_valid_drivename
($value);
2169 return undef if $noerr;
2171 die "invalid boot disk '$value'\n";
2174 sub parse_watchdog
{
2177 return undef if !$value;
2179 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2184 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2185 sub verify_usb_device
{
2186 my ($value, $noerr) = @_;
2188 return $value if parse_usb_device
($value);
2190 return undef if $noerr;
2192 die "unable to parse usb device\n";
2195 # add JSON properties for create and set function
2196 sub json_config_properties
{
2199 foreach my $opt (keys %$confdesc) {
2200 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2201 $prop->{$opt} = $confdesc->{$opt};
2208 my ($key, $value) = @_;
2210 die "unknown setting '$key'\n" if !$confdesc->{$key};
2212 my $type = $confdesc->{$key}->{type
};
2214 if (!defined($value)) {
2215 die "got undefined value\n";
2218 if ($value =~ m/[\n\r]/) {
2219 die "property contains a line feed\n";
2222 if ($type eq 'boolean') {
2223 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2224 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2225 die "type check ('boolean') failed - got '$value'\n";
2226 } elsif ($type eq 'integer') {
2227 return int($1) if $value =~ m/^(\d+)$/;
2228 die "type check ('integer') failed - got '$value'\n";
2229 } elsif ($type eq 'number') {
2230 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2231 die "type check ('number') failed - got '$value'\n";
2232 } elsif ($type eq 'string') {
2233 if (my $fmt = $confdesc->{$key}->{format
}) {
2234 PVE
::JSONSchema
::check_format
($fmt, $value);
2237 $value =~ s/^\"(.*)\"$/$1/;
2240 die "internal error"
2244 sub check_iommu_support
{
2245 #fixme : need to check IOMMU support
2246 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2256 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2257 utime undef, undef, $conf;
2261 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2263 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2265 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2267 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2269 if ($conf->{template
}) {
2270 # check if any base image is still used by a linked clone
2271 foreach_drive
($conf, sub {
2272 my ($ds, $drive) = @_;
2274 return if drive_is_cdrom
($drive);
2276 my $volid = $drive->{file
};
2278 return if !$volid || $volid =~ m
|^/|;
2280 die "base volume '$volid' is still in use by linked cloned\n"
2281 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2286 # only remove disks owned by this VM
2287 foreach_drive
($conf, sub {
2288 my ($ds, $drive) = @_;
2290 return if drive_is_cdrom
($drive);
2292 my $volid = $drive->{file
};
2294 return if !$volid || $volid =~ m
|^/|;
2296 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2297 return if !$path || !$owner || ($owner != $vmid);
2300 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2302 warn "Could not remove disk '$volid', check manually: $@" if $@;
2306 if ($keep_empty_config) {
2307 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2312 # also remove unused disk
2314 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2317 PVE
::Storage
::foreach_volid
($dl, sub {
2318 my ($volid, $sid, $volname, $d) = @_;
2319 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2328 sub parse_vm_config
{
2329 my ($filename, $raw) = @_;
2331 return undef if !defined($raw);
2334 digest
=> Digest
::SHA
::sha1_hex
($raw),
2339 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2340 || die "got strange filename '$filename'";
2348 my @lines = split(/\n/, $raw);
2349 foreach my $line (@lines) {
2350 next if $line =~ m/^\s*$/;
2352 if ($line =~ m/^\[PENDING\]\s*$/i) {
2353 $section = 'pending';
2354 if (defined($descr)) {
2356 $conf->{description
} = $descr;
2359 $conf = $res->{$section} = {};
2362 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2364 if (defined($descr)) {
2366 $conf->{description
} = $descr;
2369 $conf = $res->{snapshots
}->{$section} = {};
2373 if ($line =~ m/^\#(.*)\s*$/) {
2374 $descr = '' if !defined($descr);
2375 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2379 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2380 $descr = '' if !defined($descr);
2381 $descr .= PVE
::Tools
::decode_text
($2);
2382 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2383 $conf->{snapstate
} = $1;
2384 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2387 $conf->{$key} = $value;
2388 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2390 if ($section eq 'pending') {
2391 $conf->{delete} = $value; # we parse this later
2393 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2395 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2398 eval { $value = check_type
($key, $value); };
2400 warn "vm $vmid - unable to parse value of '$key' - $@";
2402 $key = 'ide2' if $key eq 'cdrom';
2403 my $fmt = $confdesc->{$key}->{format
};
2404 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2405 my $v = parse_drive
($key, $value);
2406 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2407 $v->{file
} = $volid;
2408 $value = print_drive
($vmid, $v);
2410 warn "vm $vmid - unable to parse value of '$key'\n";
2415 $conf->{$key} = $value;
2420 if (defined($descr)) {
2422 $conf->{description
} = $descr;
2424 delete $res->{snapstate
}; # just to be sure
2429 sub write_vm_config
{
2430 my ($filename, $conf) = @_;
2432 delete $conf->{snapstate
}; # just to be sure
2434 if ($conf->{cdrom
}) {
2435 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2436 $conf->{ide2
} = $conf->{cdrom
};
2437 delete $conf->{cdrom
};
2440 # we do not use 'smp' any longer
2441 if ($conf->{sockets
}) {
2442 delete $conf->{smp
};
2443 } elsif ($conf->{smp
}) {
2444 $conf->{sockets
} = $conf->{smp
};
2445 delete $conf->{cores
};
2446 delete $conf->{smp
};
2449 my $used_volids = {};
2451 my $cleanup_config = sub {
2452 my ($cref, $pending, $snapname) = @_;
2454 foreach my $key (keys %$cref) {
2455 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2456 $key eq 'snapstate' || $key eq 'pending';
2457 my $value = $cref->{$key};
2458 if ($key eq 'delete') {
2459 die "propertry 'delete' is only allowed in [PENDING]\n"
2461 # fixme: check syntax?
2464 eval { $value = check_type
($key, $value); };
2465 die "unable to parse value of '$key' - $@" if $@;
2467 $cref->{$key} = $value;
2469 if (!$snapname && is_valid_drivename
($key)) {
2470 my $drive = parse_drive
($key, $value);
2471 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2476 &$cleanup_config($conf);
2478 &$cleanup_config($conf->{pending
}, 1);
2480 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2481 die "internal error" if $snapname eq 'pending';
2482 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2485 # remove 'unusedX' settings if we re-add a volume
2486 foreach my $key (keys %$conf) {
2487 my $value = $conf->{$key};
2488 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2489 delete $conf->{$key};
2493 my $generate_raw_config = sub {
2494 my ($conf, $pending) = @_;
2498 # add description as comment to top of file
2499 if (defined(my $descr = $conf->{description
})) {
2501 foreach my $cl (split(/\n/, $descr)) {
2502 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2505 $raw .= "#\n" if $pending;
2509 foreach my $key (sort keys %$conf) {
2510 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2511 $raw .= "$key: $conf->{$key}\n";
2516 my $raw = &$generate_raw_config($conf);
2518 if (scalar(keys %{$conf->{pending
}})){
2519 $raw .= "\n[PENDING]\n";
2520 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2523 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2524 $raw .= "\n[$snapname]\n";
2525 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2535 # we use static defaults from our JSON schema configuration
2536 foreach my $key (keys %$confdesc) {
2537 if (defined(my $default = $confdesc->{$key}->{default})) {
2538 $res->{$key} = $default;
2542 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2543 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2549 my $vmlist = PVE
::Cluster
::get_vmlist
();
2551 return $res if !$vmlist || !$vmlist->{ids
};
2552 my $ids = $vmlist->{ids
};
2554 foreach my $vmid (keys %$ids) {
2555 my $d = $ids->{$vmid};
2556 next if !$d->{node
} || $d->{node
} ne $nodename;
2557 next if !$d->{type
} || $d->{type
} ne 'qemu';
2558 $res->{$vmid}->{exists} = 1;
2563 # test if VM uses local resources (to prevent migration)
2564 sub check_local_resources
{
2565 my ($conf, $noerr) = @_;
2569 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2570 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2572 foreach my $k (keys %$conf) {
2573 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2574 # sockets are safe: they will recreated be on the target side post-migrate
2575 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2576 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2579 die "VM uses local resources\n" if $loc_res && !$noerr;
2584 # check if used storages are available on all nodes (use by migrate)
2585 sub check_storage_availability
{
2586 my ($storecfg, $conf, $node) = @_;
2588 foreach_drive
($conf, sub {
2589 my ($ds, $drive) = @_;
2591 my $volid = $drive->{file
};
2594 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2597 # check if storage is available on both nodes
2598 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2599 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2603 # list nodes where all VM images are available (used by has_feature API)
2605 my ($conf, $storecfg) = @_;
2607 my $nodelist = PVE
::Cluster
::get_nodelist
();
2608 my $nodehash = { map { $_ => 1 } @$nodelist };
2609 my $nodename = PVE
::INotify
::nodename
();
2611 foreach_drive
($conf, sub {
2612 my ($ds, $drive) = @_;
2614 my $volid = $drive->{file
};
2617 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2619 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2620 if ($scfg->{disable
}) {
2622 } elsif (my $avail = $scfg->{nodes
}) {
2623 foreach my $node (keys %$nodehash) {
2624 delete $nodehash->{$node} if !$avail->{$node};
2626 } elsif (!$scfg->{shared
}) {
2627 foreach my $node (keys %$nodehash) {
2628 delete $nodehash->{$node} if $node ne $nodename
2638 my ($pidfile, $pid) = @_;
2640 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2644 return undef if !$line;
2645 my @param = split(/\0/, $line);
2647 my $cmd = $param[0];
2648 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2650 for (my $i = 0; $i < scalar (@param); $i++) {
2653 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2654 my $p = $param[$i+1];
2655 return 1 if $p && ($p eq $pidfile);
2664 my ($vmid, $nocheck, $node) = @_;
2666 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2668 die "unable to find configuration file for VM $vmid - no such machine\n"
2669 if !$nocheck && ! -f
$filename;
2671 my $pidfile = pidfile_name
($vmid);
2673 if (my $fd = IO
::File-
>new("<$pidfile")) {
2678 my $mtime = $st->mtime;
2679 if ($mtime > time()) {
2680 warn "file '$filename' modified in future\n";
2683 if ($line =~ m/^(\d+)$/) {
2685 if (check_cmdline
($pidfile, $pid)) {
2686 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2698 my $vzlist = config_list
();
2700 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2702 while (defined(my $de = $fd->read)) {
2703 next if $de !~ m/^(\d+)\.pid$/;
2705 next if !defined($vzlist->{$vmid});
2706 if (my $pid = check_running
($vmid)) {
2707 $vzlist->{$vmid}->{pid
} = $pid;
2715 my ($storecfg, $conf) = @_;
2717 my $bootdisk = $conf->{bootdisk
};
2718 return undef if !$bootdisk;
2719 return undef if !is_valid_drivename
($bootdisk);
2721 return undef if !$conf->{$bootdisk};
2723 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2724 return undef if !defined($drive);
2726 return undef if drive_is_cdrom
($drive);
2728 my $volid = $drive->{file
};
2729 return undef if !$volid;
2731 return $drive->{size
};
2734 my $last_proc_pid_stat;
2736 # get VM status information
2737 # This must be fast and should not block ($full == false)
2738 # We only query KVM using QMP if $full == true (this can be slow)
2740 my ($opt_vmid, $full) = @_;
2744 my $storecfg = PVE
::Storage
::config
();
2746 my $list = vzlist
();
2747 my $defaults = load_defaults
();
2749 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2751 my $cpucount = $cpuinfo->{cpus
} || 1;
2753 foreach my $vmid (keys %$list) {
2754 next if $opt_vmid && ($vmid ne $opt_vmid);
2756 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2757 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2760 $d->{pid
} = $list->{$vmid}->{pid
};
2762 # fixme: better status?
2763 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2765 my $size = disksize
($storecfg, $conf);
2766 if (defined($size)) {
2767 $d->{disk
} = 0; # no info available
2768 $d->{maxdisk
} = $size;
2774 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2775 * ($conf->{cores
} || $defaults->{cores
});
2776 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2777 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2779 $d->{name
} = $conf->{name
} || "VM $vmid";
2780 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2781 : $defaults->{memory
}*(1024*1024);
2783 if ($conf->{balloon
}) {
2784 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2785 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2786 : $defaults->{shares
};
2797 $d->{diskwrite
} = 0;
2799 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2801 $d->{serial
} = 1 if conf_has_serial
($conf);
2806 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2807 foreach my $dev (keys %$netdev) {
2808 next if $dev !~ m/^tap([1-9]\d*)i/;
2810 my $d = $res->{$vmid};
2813 $d->{netout
} += $netdev->{$dev}->{receive
};
2814 $d->{netin
} += $netdev->{$dev}->{transmit
};
2817 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2818 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2823 my $ctime = gettimeofday
;
2825 foreach my $vmid (keys %$list) {
2827 my $d = $res->{$vmid};
2828 my $pid = $d->{pid
};
2831 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2832 next if !$pstat; # not running
2834 my $used = $pstat->{utime} + $pstat->{stime
};
2836 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2838 if ($pstat->{vsize
}) {
2839 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2842 my $old = $last_proc_pid_stat->{$pid};
2844 $last_proc_pid_stat->{$pid} = {
2852 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2854 if ($dtime > 1000) {
2855 my $dutime = $used - $old->{used
};
2857 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2858 $last_proc_pid_stat->{$pid} = {
2864 $d->{cpu
} = $old->{cpu
};
2868 return $res if !$full;
2870 my $qmpclient = PVE
::QMPClient-
>new();
2872 my $ballooncb = sub {
2873 my ($vmid, $resp) = @_;
2875 my $info = $resp->{'return'};
2876 return if !$info->{max_mem
};
2878 my $d = $res->{$vmid};
2880 # use memory assigned to VM
2881 $d->{maxmem
} = $info->{max_mem
};
2882 $d->{balloon
} = $info->{actual
};
2884 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2885 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2886 $d->{freemem
} = $info->{free_mem
};
2889 $d->{ballooninfo
} = $info;
2892 my $blockstatscb = sub {
2893 my ($vmid, $resp) = @_;
2894 my $data = $resp->{'return'} || [];
2895 my $totalrdbytes = 0;
2896 my $totalwrbytes = 0;
2898 for my $blockstat (@$data) {
2899 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2900 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2902 $blockstat->{device
} =~ s/drive-//;
2903 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2905 $res->{$vmid}->{diskread
} = $totalrdbytes;
2906 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2909 my $statuscb = sub {
2910 my ($vmid, $resp) = @_;
2912 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2913 # this fails if ballon driver is not loaded, so this must be
2914 # the last commnand (following command are aborted if this fails).
2915 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2917 my $status = 'unknown';
2918 if (!defined($status = $resp->{'return'}->{status
})) {
2919 warn "unable to get VM status\n";
2923 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2926 foreach my $vmid (keys %$list) {
2927 next if $opt_vmid && ($vmid ne $opt_vmid);
2928 next if !$res->{$vmid}->{pid
}; # not running
2929 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2932 $qmpclient->queue_execute(undef, 2);
2934 foreach my $vmid (keys %$list) {
2935 next if $opt_vmid && ($vmid ne $opt_vmid);
2936 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2943 my ($conf, $func, @param) = @_;
2945 foreach my $ds (valid_drive_names
()) {
2946 next if !defined($conf->{$ds});
2948 my $drive = parse_drive
($ds, $conf->{$ds});
2951 &$func($ds, $drive, @param);
2956 my ($conf, $func, @param) = @_;
2960 my $test_volid = sub {
2961 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
2965 $volhash->{$volid}->{cdrom
} //= 1;
2966 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
2968 $volhash->{$volid}->{replicate
} //= 0;
2969 $volhash->{$volid}->{replicate
} = 1 if $replicate;
2971 $volhash->{$volid}->{shared
} //= 0;
2972 $volhash->{$volid}->{shared
} = 1 if $shared;
2974 $volhash->{$volid}->{referenced_in_config
} //= 0;
2975 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
2977 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
2978 if defined($snapname);
2981 foreach_drive
($conf, sub {
2982 my ($ds, $drive) = @_;
2983 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
2986 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2987 my $snap = $conf->{snapshots
}->{$snapname};
2988 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
2989 foreach_drive
($snap, sub {
2990 my ($ds, $drive) = @_;
2991 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
2995 foreach my $volid (keys %$volhash) {
2996 &$func($volid, $volhash->{$volid}, @param);
3000 sub conf_has_serial
{
3003 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3004 if ($conf->{"serial$i"}) {
3012 sub vga_conf_has_spice
{
3015 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3020 sub config_to_command
{
3021 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3024 my $globalFlags = [];
3025 my $machineFlags = [];
3031 my $kvmver = kvm_user_version
();
3032 my $vernum = 0; # unknown
3033 my $ostype = $conf->{ostype
};
3034 my $winversion = windows_version
($ostype);
3035 my $kvm = $conf->{kvm
} // 1;
3037 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3039 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3040 $vernum = $1*1000000+$2*1000;
3041 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3042 $vernum = $1*1000000+$2*1000+$3;
3045 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3047 my $have_ovz = -f
'/proc/vz/vestat';
3049 my $q35 = machine_type_is_q35
($conf);
3050 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3051 my $machine_type = $forcemachine || $conf->{machine
};
3052 my $use_old_bios_files = undef;
3053 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3055 my $cpuunits = defined($conf->{cpuunits
}) ?
3056 $conf->{cpuunits
} : $defaults->{cpuunits
};
3058 push @$cmd, '/usr/bin/kvm';
3060 push @$cmd, '-id', $vmid;
3064 my $qmpsocket = qmp_socket
($vmid);
3065 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3066 push @$cmd, '-mon', "chardev=qmp,mode=control";
3069 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3071 push @$cmd, '-daemonize';
3073 if ($conf->{smbios1
}) {
3074 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3077 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3078 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3082 if (my $efidisk = $conf->{efidisk0
}) {
3083 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3084 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3085 $format = $d->{format
};
3087 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3088 if (!defined($format)) {
3089 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3090 $format = qemu_img_format
($scfg, $volname);
3094 die "efidisk format must be specified\n"
3095 if !defined($format);
3098 warn "no efidisk configured! Using temporary efivars disk.\n";
3099 $path = "/tmp/$vmid-ovmf.fd";
3100 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3104 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3105 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3109 # add usb controllers
3110 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3111 push @$devices, @usbcontrollers if @usbcontrollers;
3112 my $vga = $conf->{vga
};
3114 my $qxlnum = vga_conf_has_spice
($vga);
3115 $vga = 'qxl' if $qxlnum;
3118 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3119 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3121 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3125 # enable absolute mouse coordinates (needed by vnc)
3127 if (defined($conf->{tablet
})) {
3128 $tablet = $conf->{tablet
};
3130 $tablet = $defaults->{tablet
};
3131 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3132 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3135 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3138 my $gpu_passthrough;
3141 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3142 my $d = parse_hostpci
($conf->{"hostpci$i"});
3145 my $pcie = $d->{pcie
};
3147 die "q35 machine model is not enabled" if !$q35;
3148 $pciaddr = print_pcie_addr
("hostpci$i");
3150 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3153 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3154 my $romfile = $d->{romfile
};
3157 if ($d->{'x-vga'}) {
3158 $xvga = ',x-vga=on';
3161 $gpu_passthrough = 1;
3163 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3167 my $pcidevices = $d->{pciid
};
3168 my $multifunction = 1 if @$pcidevices > 1;
3171 foreach my $pcidevice (@$pcidevices) {
3173 my $id = "hostpci$i";
3174 $id .= ".$j" if $multifunction;
3175 my $addr = $pciaddr;
3176 $addr .= ".$j" if $multifunction;
3177 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3180 $devicestr .= "$rombar$xvga";
3181 $devicestr .= ",multifunction=on" if $multifunction;
3182 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3185 push @$devices, '-device', $devicestr;
3191 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3192 push @$devices, @usbdevices if @usbdevices;
3194 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3195 if (my $path = $conf->{"serial$i"}) {
3196 if ($path eq 'socket') {
3197 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3198 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3199 push @$devices, '-device', "isa-serial,chardev=serial$i";
3201 die "no such serial device\n" if ! -c
$path;
3202 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3203 push @$devices, '-device', "isa-serial,chardev=serial$i";
3209 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3210 if (my $path = $conf->{"parallel$i"}) {
3211 die "no such parallel device\n" if ! -c
$path;
3212 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3213 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3214 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3218 my $vmname = $conf->{name
} || "vm$vmid";
3220 push @$cmd, '-name', $vmname;
3223 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3224 $sockets = $conf->{sockets
} if $conf->{sockets
};
3226 my $cores = $conf->{cores
} || 1;
3228 my $maxcpus = $sockets * $cores;
3230 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3232 my $allowed_vcpus = $cpuinfo->{cpus
};
3234 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3235 if ($allowed_vcpus < $maxcpus);
3237 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3239 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3240 for (my $i = 2; $i <= $vcpus; $i++) {
3241 my $cpustr = print_cpu_device
($conf,$i);
3242 push @$cmd, '-device', $cpustr;
3247 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3249 push @$cmd, '-nodefaults';
3251 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3253 my $bootindex_hash = {};
3255 foreach my $o (split(//, $bootorder)) {
3256 $bootindex_hash->{$o} = $i*100;
3260 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3262 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3264 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3266 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3268 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3269 my $socket = vnc_socket
($vmid);
3270 push @$cmd, '-vnc', "unix:$socket,x509,password";
3272 push @$cmd, '-nographic';
3276 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3278 my $useLocaltime = $conf->{localtime};
3280 if ($winversion >= 5) { # windows
3281 $useLocaltime = 1 if !defined($conf->{localtime});
3283 # use time drift fix when acpi is enabled
3284 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3285 $tdf = 1 if !defined($conf->{tdf
});
3289 if ($winversion >= 6) {
3290 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3291 push @$cmd, '-no-hpet';
3294 push @$rtcFlags, 'driftfix=slew' if $tdf;
3297 push @$machineFlags, 'accel=tcg';
3300 if ($machine_type) {
3301 push @$machineFlags, "type=${machine_type}";
3304 if ($conf->{startdate
}) {
3305 push @$rtcFlags, "base=$conf->{startdate}";
3306 } elsif ($useLocaltime) {
3307 push @$rtcFlags, 'base=localtime';
3310 my $cpu = $kvm ?
"kvm64" : "qemu64";
3311 if (my $cputype = $conf->{cpu
}) {
3312 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3313 or die "Cannot parse cpu description: $cputype\n";
3314 $cpu = $cpuconf->{cputype
};
3315 $kvm_off = 1 if $cpuconf->{hidden
};
3317 if (defined(my $flags = $cpuconf->{flags
})) {
3318 push @$cpuFlags, split(";", $flags);
3322 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3324 push @$cpuFlags , '-x2apic'
3325 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3327 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3329 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3331 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3333 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3334 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3337 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3339 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3341 push @$cpuFlags, 'kvm=off' if $kvm_off;
3343 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3344 die "internal error"; # should not happen
3346 push @$cpuFlags, "vendor=${cpu_vendor}"
3347 if $cpu_vendor ne 'default';
3349 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3351 push @$cmd, '-cpu', $cpu;
3353 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3355 push @$cmd, '-S' if $conf->{freeze
};
3357 # set keyboard layout
3358 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3359 push @$cmd, '-k', $kb if $kb;
3362 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3363 #push @$cmd, '-soundhw', 'es1370';
3364 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3366 if($conf->{agent
}) {
3367 my $qgasocket = qmp_socket
($vmid, 1);
3368 my $pciaddr = print_pci_addr
("qga0", $bridges);
3369 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3370 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3371 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3379 for(my $i = 1; $i < $qxlnum; $i++){
3380 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3381 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3384 # assume other OS works like Linux
3385 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3386 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3390 my $pciaddr = print_pci_addr
("spice", $bridges);
3392 my $nodename = PVE
::INotify
::nodename
();
3393 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3394 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3395 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3396 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3397 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3399 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3401 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3402 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3403 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3406 # enable balloon by default, unless explicitly disabled
3407 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3408 $pciaddr = print_pci_addr
("balloon0", $bridges);
3409 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3412 if ($conf->{watchdog
}) {
3413 my $wdopts = parse_watchdog
($conf->{watchdog
});
3414 $pciaddr = print_pci_addr
("watchdog", $bridges);
3415 my $watchdog = $wdopts->{model
} || 'i6300esb';
3416 push @$devices, '-device', "$watchdog$pciaddr";
3417 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3421 my $scsicontroller = {};
3422 my $ahcicontroller = {};
3423 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3425 # Add iscsi initiator name if available
3426 if (my $initiator = get_initiator_name
()) {
3427 push @$devices, '-iscsi', "initiator-name=$initiator";
3430 foreach_drive
($conf, sub {
3431 my ($ds, $drive) = @_;
3433 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3434 push @$vollist, $drive->{file
};
3437 # ignore efidisk here, already added in bios/fw handling code above
3438 return if $drive->{interface
} eq 'efidisk';
3440 $use_virtio = 1 if $ds =~ m/^virtio/;
3442 if (drive_is_cdrom
($drive)) {
3443 if ($bootindex_hash->{d
}) {
3444 $drive->{bootindex
} = $bootindex_hash->{d
};
3445 $bootindex_hash->{d
} += 1;
3448 if ($bootindex_hash->{c
}) {
3449 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3450 $bootindex_hash->{c
} += 1;
3454 if($drive->{interface
} eq 'virtio'){
3455 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3458 if ($drive->{interface
} eq 'scsi') {
3460 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3462 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3463 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3466 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3467 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3468 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3469 } elsif ($drive->{iothread
}) {
3470 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3474 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3475 $queues = ",num_queues=$drive->{queues}";
3478 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3479 $scsicontroller->{$controller}=1;
3482 if ($drive->{interface
} eq 'sata') {
3483 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3484 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3485 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3486 $ahcicontroller->{$controller}=1;
3489 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3490 push @$devices, '-drive',$drive_cmd;
3491 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3494 for (my $i = 0; $i < $MAX_NETS; $i++) {
3495 next if !$conf->{"net$i"};
3496 my $d = parse_net
($conf->{"net$i"});
3499 $use_virtio = 1 if $d->{model
} eq 'virtio';
3501 if ($bootindex_hash->{n
}) {
3502 $d->{bootindex
} = $bootindex_hash->{n
};
3503 $bootindex_hash->{n
} += 1;
3506 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3507 push @$devices, '-netdev', $netdevfull;
3509 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3510 push @$devices, '-device', $netdevicefull;
3515 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3520 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3522 while (my ($k, $v) = each %$bridges) {
3523 $pciaddr = print_pci_addr
("pci.$k");
3524 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3529 if ($conf->{args
}) {
3530 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3534 push @$cmd, @$devices;
3535 push @$cmd, '-rtc', join(',', @$rtcFlags)
3536 if scalar(@$rtcFlags);
3537 push @$cmd, '-machine', join(',', @$machineFlags)
3538 if scalar(@$machineFlags);
3539 push @$cmd, '-global', join(',', @$globalFlags)
3540 if scalar(@$globalFlags);
3542 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3547 return "${var_run_tmpdir}/$vmid.vnc";
3553 my $res = vm_mon_cmd
($vmid, 'query-spice');
3555 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3559 my ($vmid, $qga) = @_;
3560 my $sockettype = $qga ?
'qga' : 'qmp';
3561 return "${var_run_tmpdir}/$vmid.$sockettype";
3566 return "${var_run_tmpdir}/$vmid.pid";
3569 sub vm_devices_list
{
3572 my $res = vm_mon_cmd
($vmid, 'query-pci');
3574 foreach my $pcibus (@$res) {
3575 foreach my $device (@{$pcibus->{devices
}}) {
3576 next if !$device->{'qdev_id'};
3577 if ($device->{'pci_bridge'}) {
3578 $devices->{$device->{'qdev_id'}} = 1;
3579 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3580 next if !$bridge_device->{'qdev_id'};
3581 $devices->{$bridge_device->{'qdev_id'}} = 1;
3582 $devices->{$device->{'qdev_id'}}++;
3585 $devices->{$device->{'qdev_id'}} = 1;
3590 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3591 foreach my $block (@$resblock) {
3592 if($block->{device
} =~ m/^drive-(\S+)/){
3597 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3598 foreach my $mice (@$resmice) {
3599 if ($mice->{name
} eq 'QEMU HID Tablet') {
3600 $devices->{tablet
} = 1;
3605 # for usb devices there is no query-usb
3606 # but we can iterate over the entries in
3607 # qom-list path=/machine/peripheral
3608 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3609 foreach my $per (@$resperipheral) {
3610 if ($per->{name
} =~ m/^usb\d+$/) {
3611 $devices->{$per->{name
}} = 1;
3619 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3621 my $q35 = machine_type_is_q35
($conf);
3623 my $devices_list = vm_devices_list
($vmid);
3624 return 1 if defined($devices_list->{$deviceid});
3626 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3628 if ($deviceid eq 'tablet') {
3630 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3632 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3634 die "usb hotplug currently not reliable\n";
3635 # since we can't reliably hot unplug all added usb devices
3636 # and usb passthrough disables live migration
3637 # we disable usb hotplugging for now
3638 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3640 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3642 qemu_iothread_add
($vmid, $deviceid, $device);
3644 qemu_driveadd
($storecfg, $vmid, $device);
3645 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3647 qemu_deviceadd
($vmid, $devicefull);
3648 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3650 eval { qemu_drivedel
($vmid, $deviceid); };
3655 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3658 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3659 my $pciaddr = print_pci_addr
($deviceid);
3660 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3662 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3664 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3665 qemu_iothread_add
($vmid, $deviceid, $device);
3666 $devicefull .= ",iothread=iothread-$deviceid";
3669 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3670 $devicefull .= ",num_queues=$device->{queues}";
3673 qemu_deviceadd
($vmid, $devicefull);
3674 qemu_deviceaddverify
($vmid, $deviceid);
3676 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3678 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3679 qemu_driveadd
($storecfg, $vmid, $device);
3681 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3682 eval { qemu_deviceadd
($vmid, $devicefull); };
3684 eval { qemu_drivedel
($vmid, $deviceid); };
3689 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3691 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3693 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3694 my $use_old_bios_files = undef;
3695 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3697 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3698 qemu_deviceadd
($vmid, $netdevicefull);
3699 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3701 eval { qemu_netdevdel
($vmid, $deviceid); };
3706 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3709 my $pciaddr = print_pci_addr
($deviceid);
3710 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3712 qemu_deviceadd
($vmid, $devicefull);
3713 qemu_deviceaddverify
($vmid, $deviceid);
3716 die "can't hotplug device '$deviceid'\n";
3722 # fixme: this should raise exceptions on error!
3723 sub vm_deviceunplug
{
3724 my ($vmid, $conf, $deviceid) = @_;
3726 my $devices_list = vm_devices_list
($vmid);
3727 return 1 if !defined($devices_list->{$deviceid});
3729 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3731 if ($deviceid eq 'tablet') {
3733 qemu_devicedel
($vmid, $deviceid);
3735 } elsif ($deviceid =~ m/^usb\d+$/) {
3737 die "usb hotplug currently not reliable\n";
3738 # when unplugging usb devices this way,
3739 # there may be remaining usb controllers/hubs
3740 # so we disable it for now
3741 qemu_devicedel
($vmid, $deviceid);
3742 qemu_devicedelverify
($vmid, $deviceid);
3744 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3746 qemu_devicedel
($vmid, $deviceid);
3747 qemu_devicedelverify
($vmid, $deviceid);
3748 qemu_drivedel
($vmid, $deviceid);
3749 qemu_iothread_del
($conf, $vmid, $deviceid);
3751 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3753 qemu_devicedel
($vmid, $deviceid);
3754 qemu_devicedelverify
($vmid, $deviceid);
3755 qemu_iothread_del
($conf, $vmid, $deviceid);
3757 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3759 qemu_devicedel
($vmid, $deviceid);
3760 qemu_drivedel
($vmid, $deviceid);
3761 qemu_deletescsihw
($conf, $vmid, $deviceid);
3763 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3765 qemu_devicedel
($vmid, $deviceid);
3766 qemu_devicedelverify
($vmid, $deviceid);
3767 qemu_netdevdel
($vmid, $deviceid);
3770 die "can't unplug device '$deviceid'\n";
3776 sub qemu_deviceadd
{
3777 my ($vmid, $devicefull) = @_;
3779 $devicefull = "driver=".$devicefull;
3780 my %options = split(/[=,]/, $devicefull);
3782 vm_mon_cmd
($vmid, "device_add" , %options);
3785 sub qemu_devicedel
{
3786 my ($vmid, $deviceid) = @_;
3788 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3791 sub qemu_iothread_add
{
3792 my($vmid, $deviceid, $device) = @_;
3794 if ($device->{iothread
}) {
3795 my $iothreads = vm_iothreads_list
($vmid);
3796 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3800 sub qemu_iothread_del
{
3801 my($conf, $vmid, $deviceid) = @_;
3803 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3804 if ($device->{iothread
}) {
3805 my $iothreads = vm_iothreads_list
($vmid);
3806 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3810 sub qemu_objectadd
{
3811 my($vmid, $objectid, $qomtype) = @_;
3813 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3818 sub qemu_objectdel
{
3819 my($vmid, $objectid) = @_;
3821 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3827 my ($storecfg, $vmid, $device) = @_;
3829 my $drive = print_drive_full
($storecfg, $vmid, $device);
3830 $drive =~ s/\\/\\\\/g;
3831 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3833 # If the command succeeds qemu prints: "OK
"
3834 return 1 if $ret =~ m/OK/s;
3836 die "adding drive failed
: $ret\n";
3840 my($vmid, $deviceid) = @_;
3842 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3845 return 1 if $ret eq "";
3847 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3848 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3850 die "deleting drive
$deviceid failed
: $ret\n";
3853 sub qemu_deviceaddverify {
3854 my ($vmid, $deviceid) = @_;
3856 for (my $i = 0; $i <= 5; $i++) {
3857 my $devices_list = vm_devices_list($vmid);
3858 return 1 if defined($devices_list->{$deviceid});
3862 die "error on hotplug device
'$deviceid'\n";
3866 sub qemu_devicedelverify {
3867 my ($vmid, $deviceid) = @_;
3869 # need to verify that the device is correctly removed as device_del
3870 # is async and empty return is not reliable
3872 for (my $i = 0; $i <= 5; $i++) {
3873 my $devices_list = vm_devices_list($vmid);
3874 return 1 if !defined($devices_list->{$deviceid});
3878 die "error on hot-unplugging device
'$deviceid'\n";
3881 sub qemu_findorcreatescsihw {
3882 my ($storecfg, $conf, $vmid, $device) = @_;
3884 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3886 my $scsihwid="$controller_prefix$controller";
3887 my $devices_list = vm_devices_list($vmid);
3889 if(!defined($devices_list->{$scsihwid})) {
3890 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3896 sub qemu_deletescsihw {
3897 my ($conf, $vmid, $opt) = @_;
3899 my $device = parse_drive($opt, $conf->{$opt});
3901 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3902 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3906 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3908 my $devices_list = vm_devices_list($vmid);
3909 foreach my $opt (keys %{$devices_list}) {
3910 if (PVE::QemuServer::is_valid_drivename($opt)) {
3911 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3912 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3918 my $scsihwid="scsihw
$controller";
3920 vm_deviceunplug($vmid, $conf, $scsihwid);
3925 sub qemu_add_pci_bridge {
3926 my ($storecfg, $conf, $vmid, $device) = @_;
3932 print_pci_addr($device, $bridges);
3934 while (my ($k, $v) = each %$bridges) {
3937 return 1 if !defined($bridgeid) || $bridgeid < 1;
3939 my $bridge = "pci
.$bridgeid";
3940 my $devices_list = vm_devices_list($vmid);
3942 if (!defined($devices_list->{$bridge})) {
3943 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3949 sub qemu_set_link_status {
3950 my ($vmid, $device, $up) = @_;
3952 vm_mon_cmd($vmid, "set_link
", name => $device,
3953 up => $up ? JSON::true : JSON::false);
3956 sub qemu_netdevadd {
3957 my ($vmid, $conf, $device, $deviceid) = @_;
3959 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3960 my %options = split(/[=,]/, $netdev);
3962 vm_mon_cmd($vmid, "netdev_add
", %options);
3966 sub qemu_netdevdel {
3967 my ($vmid, $deviceid) = @_;
3969 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
3972 sub qemu_usb_hotplug {
3973 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3977 # remove the old one first
3978 vm_deviceunplug($vmid, $conf, $deviceid);
3980 # check if xhci controller is necessary and available
3981 if ($device->{usb3}) {
3983 my $devicelist = vm_devices_list($vmid);
3985 if (!$devicelist->{xhci}) {
3986 my $pciaddr = print_pci_addr("xhci
");
3987 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
3990 my $d = parse_usb_device($device->{host});
3991 $d->{usb3} = $device->{usb3};
3994 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
3997 sub qemu_cpu_hotplug {
3998 my ($vmid, $conf, $vcpus) = @_;
4000 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4003 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4004 $sockets = $conf->{sockets} if $conf->{sockets};
4005 my $cores = $conf->{cores} || 1;
4006 my $maxcpus = $sockets * $cores;
4008 $vcpus = $maxcpus if !$vcpus;
4010 die "you can
't add more vcpus than maxcpus\n"
4011 if $vcpus > $maxcpus;
4013 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4015 if ($vcpus < $currentvcpus) {
4017 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4019 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4020 qemu_devicedel($vmid, "cpu$i");
4022 my $currentrunningvcpus = undef;
4024 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4025 last if scalar(@{$currentrunningvcpus}) == $i-1;
4026 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4030 #update conf after each succesfull cpu unplug
4031 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4032 PVE::QemuConfig->write_config($vmid, $conf);
4035 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4041 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4042 die "vcpus in running vm does not match its configuration\n"
4043 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4045 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4047 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4048 my $cpustr = print_cpu_device($conf, $i);
4049 qemu_deviceadd($vmid, $cpustr);
4052 my $currentrunningvcpus = undef;
4054 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4055 last if scalar(@{$currentrunningvcpus}) == $i;
4056 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4060 #update conf after each succesfull cpu hotplug
4061 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4062 PVE::QemuConfig->write_config($vmid, $conf);
4066 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4067 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4072 sub qemu_block_set_io_throttle {
4073 my ($vmid, $deviceid,
4074 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4075 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4076 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4077 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4079 return if !check_running($vmid) ;
4081 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4083 bps_rd => int($bps_rd),
4084 bps_wr => int($bps_wr),
4086 iops_rd => int($iops_rd),
4087 iops_wr => int($iops_wr),
4088 bps_max => int($bps_max),
4089 bps_rd_max => int($bps_rd_max),
4090 bps_wr_max => int($bps_wr_max),
4091 iops_max => int($iops_max),
4092 iops_rd_max => int($iops_rd_max),
4093 iops_wr_max => int($iops_wr_max),
4094 bps_max_length => int($bps_max_length),
4095 bps_rd_max_length => int($bps_rd_max_length),
4096 bps_wr_max_length => int($bps_wr_max_length),
4097 iops_max_length => int($iops_max_length),
4098 iops_rd_max_length => int($iops_rd_max_length),
4099 iops_wr_max_length => int($iops_wr_max_length),
4104 # old code, only used to shutdown old VM after update
4106 my ($fh, $timeout) = @_;
4108 my $sel = new IO::Select;
4115 while (scalar (@ready = $sel->can_read($timeout))) {
4117 if ($count = $fh->sysread($buf, 8192)) {
4118 if ($buf =~ /^(.*)\(qemu\) $/s) {
4125 if (!defined($count)) {
4132 die "monitor read timeout\n" if !scalar(@ready);
4137 # old code, only used to shutdown old VM after update
4138 sub vm_monitor_command {
4139 my ($vmid, $cmdstr, $nocheck) = @_;
4144 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4146 my $sname = "${var_run_tmpdir}/$vmid.mon";
4148 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
4149 die "unable to connect to VM $vmid socket - $!\n";
4153 # hack: migrate sometime blocks the monitor (when migrate_downtime
4155 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4156 $timeout = 60*60; # 1 hour
4160 my $data = __read_avail($sock, $timeout);
4162 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
4163 die "got unexpected qemu monitor banner\n";
4166 my $sel = new IO::Select;
4169 if (!scalar(my @ready = $sel->can_write($timeout))) {
4170 die "monitor write error - timeout";
4173 my $fullcmd = "$cmdstr\r";
4175 # syslog('info
', "VM $vmid monitor command: $cmdstr");
4178 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
4179 die "monitor write error - $!";
4182 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
4186 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4187 $timeout = 60*60; # 1 hour
4188 } elsif ($cmdstr =~ m/^(eject|change)/) {
4189 $timeout = 60; # note: cdrom mount command is slow
4191 if ($res = __read_avail($sock, $timeout)) {
4193 my @lines = split("\r?\n", $res);
4195 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
4197 $res = join("\n", @lines);
4205 syslog("err", "VM $vmid monitor command failed - $err");
4212 sub qemu_block_resize {
4213 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4215 my $running = check_running($vmid);
4217 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4219 return if !$running;
4221 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4225 sub qemu_volume_snapshot {
4226 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4228 my $running = check_running($vmid);
4230 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4231 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4233 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4237 sub qemu_volume_snapshot_delete {
4238 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4240 my $running = check_running($vmid);
4242 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4243 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4245 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4249 sub set_migration_caps {
4255 "auto-converge" => 1,
4257 "x-rdma-pin-all" => 0,
4262 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4264 for my $supported_capability (@$supported_capabilities) {
4266 capability => $supported_capability->{capability},
4267 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4271 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4274 my $fast_plug_option = {
4282 'vmstatestorage
' => 1,
4285 # hotplug changes in [PENDING]
4286 # $selection hash can be used to only apply specified options, for
4287 # example: { cores => 1 } (only apply changed 'cores
')
4288 # $errors ref is used to return error messages
4289 sub vmconfig_hotplug_pending {
4290 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4292 my $defaults = load_defaults();
4294 # commit values which do not have any impact on running VM first
4295 # Note: those option cannot raise errors, we we do not care about
4296 # $selection and always apply them.
4298 my $add_error = sub {
4299 my ($opt, $msg) = @_;
4300 $errors->{$opt} = "hotplug problem - $msg";
4304 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4305 if ($fast_plug_option->{$opt}) {
4306 $conf->{$opt} = $conf->{pending}->{$opt};
4307 delete $conf->{pending}->{$opt};
4313 PVE::QemuConfig->write_config($vmid, $conf);
4314 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4317 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4319 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4320 while (my ($opt, $force) = each %$pending_delete_hash) {
4321 next if $selection && !$selection->{$opt};
4323 if ($opt eq 'hotplug
') {
4324 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4325 } elsif ($opt eq 'tablet
') {
4326 die "skip\n" if !$hotplug_features->{usb};
4327 if ($defaults->{tablet}) {
4328 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4330 vm_deviceunplug($vmid, $conf, $opt);
4332 } elsif ($opt =~ m/^usb\d+/) {
4334 # since we cannot reliably hot unplug usb devices
4335 # we are disabling it
4336 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4337 vm_deviceunplug($vmid, $conf, $opt);
4338 } elsif ($opt eq 'vcpus
') {
4339 die "skip\n" if !$hotplug_features->{cpu};
4340 qemu_cpu_hotplug($vmid, $conf, undef);
4341 } elsif ($opt eq 'balloon
') {
4342 # enable balloon device is not hotpluggable
4343 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4344 } elsif ($fast_plug_option->{$opt}) {
4346 } elsif ($opt =~ m/^net(\d+)$/) {
4347 die "skip\n" if !$hotplug_features->{network};
4348 vm_deviceunplug($vmid, $conf, $opt);
4349 } elsif (is_valid_drivename($opt)) {
4350 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4351 vm_deviceunplug($vmid, $conf, $opt);
4352 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4353 } elsif ($opt =~ m/^memory$/) {
4354 die "skip\n" if !$hotplug_features->{memory};
4355 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4356 } elsif ($opt eq 'cpuunits
') {
4357 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4358 } elsif ($opt eq 'cpulimit
') {
4359 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4365 &$add_error($opt, $err) if $err ne "skip\n";
4367 # save new config if hotplug was successful
4368 delete $conf->{$opt};
4369 vmconfig_undelete_pending_option($conf, $opt);
4370 PVE::QemuConfig->write_config($vmid, $conf);
4371 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4375 foreach my $opt (keys %{$conf->{pending}}) {
4376 next if $selection && !$selection->{$opt};
4377 my $value = $conf->{pending}->{$opt};
4379 if ($opt eq 'hotplug
') {
4380 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4381 } elsif ($opt eq 'tablet
') {
4382 die "skip\n" if !$hotplug_features->{usb};
4384 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4385 } elsif ($value == 0) {
4386 vm_deviceunplug($vmid, $conf, $opt);
4388 } elsif ($opt =~ m/^usb\d+$/) {
4390 # since we cannot reliably hot unplug usb devices
4391 # we are disabling it
4392 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4393 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4394 die "skip\n" if !$d;
4395 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4396 } elsif ($opt eq 'vcpus
') {
4397 die "skip\n" if !$hotplug_features->{cpu};
4398 qemu_cpu_hotplug($vmid, $conf, $value);
4399 } elsif ($opt eq 'balloon
') {
4400 # enable/disable balloning device is not hotpluggable
4401 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4402 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4403 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4405 # allow manual ballooning if shares is set to zero
4406 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4407 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4408 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4410 } elsif ($opt =~ m/^net(\d+)$/) {
4411 # some changes can be done without hotplug
4412 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4413 $vmid, $opt, $value);
4414 } elsif (is_valid_drivename($opt)) {
4415 # some changes can be done without hotplug
4416 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4417 $vmid, $opt, $value, 1);
4418 } elsif ($opt =~ m/^memory$/) { #dimms
4419 die "skip\n" if !$hotplug_features->{memory};
4420 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4421 } elsif ($opt eq 'cpuunits
') {
4422 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4423 } elsif ($opt eq 'cpulimit
') {
4424 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4425 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4427 die "skip\n"; # skip non-hot-pluggable options
4431 &$add_error($opt, $err) if $err ne "skip\n";
4433 # save new config if hotplug was successful
4434 $conf->{$opt} = $value;
4435 delete $conf->{pending}->{$opt};
4436 PVE::QemuConfig->write_config($vmid, $conf);
4437 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4442 sub try_deallocate_drive {
4443 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4445 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4446 my $volid = $drive->{file};
4447 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4448 my $sid = PVE::Storage::parse_volume_id($volid);
4449 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4451 # check if the disk is really unused
4452 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4453 if is_volume_in_use($storecfg, $conf, $key, $volid);
4454 PVE::Storage::vdisk_free($storecfg, $volid);
4457 # If vm is not owner of this disk remove from config
4465 sub vmconfig_delete_or_detach_drive {
4466 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4468 my $drive = parse_drive($opt, $conf->{$opt});
4470 my $rpcenv = PVE::RPCEnvironment::get();
4471 my $authuser = $rpcenv->get_user();
4474 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4475 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4477 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4481 sub vmconfig_apply_pending {
4482 my ($vmid, $conf, $storecfg) = @_;
4486 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4487 while (my ($opt, $force) = each %$pending_delete_hash) {
4488 die "internal error" if $opt =~ m/^unused/;
4489 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4490 if (!defined($conf->{$opt})) {
4491 vmconfig_undelete_pending_option($conf, $opt);
4492 PVE::QemuConfig->write_config($vmid, $conf);
4493 } elsif (is_valid_drivename($opt)) {
4494 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4495 vmconfig_undelete_pending_option($conf, $opt);
4496 delete $conf->{$opt};
4497 PVE::QemuConfig->write_config($vmid, $conf);
4499 vmconfig_undelete_pending_option($conf, $opt);
4500 delete $conf->{$opt};
4501 PVE::QemuConfig->write_config($vmid, $conf);
4505 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4507 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4508 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4510 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4511 # skip if nothing changed
4512 } elsif (is_valid_drivename($opt)) {
4513 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4514 if defined($conf->{$opt});
4515 $conf->{$opt} = $conf->{pending}->{$opt};
4517 $conf->{$opt} = $conf->{pending}->{$opt};
4520 delete $conf->{pending}->{$opt};
4521 PVE::QemuConfig->write_config($vmid, $conf);
4525 my $safe_num_ne = sub {
4528 return 0 if !defined($a) && !defined($b);
4529 return 1 if !defined($a);
4530 return 1 if !defined($b);
4535 my $safe_string_ne = sub {
4538 return 0 if !defined($a) && !defined($b);
4539 return 1 if !defined($a);
4540 return 1 if !defined($b);
4545 sub vmconfig_update_net {
4546 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4548 my $newnet = parse_net($value);
4550 if ($conf->{$opt}) {
4551 my $oldnet = parse_net($conf->{$opt});
4553 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4554 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4555 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4556 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4558 # for non online change, we try to hot-unplug
4559 die "skip\n" if !$hotplug;
4560 vm_deviceunplug($vmid, $conf, $opt);
4563 die "internal error" if $opt !~ m/net(\d+)/;
4564 my $iface = "tap${vmid}i$1";
4566 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4567 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4568 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4569 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4570 PVE::Network::tap_unplug($iface);
4571 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4572 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4573 # Rate can be applied on its own but any change above needs to
4574 # include the rate in tap_plug since OVS resets everything.
4575 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4578 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4579 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4587 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4593 sub vmconfig_update_disk {
4594 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4596 # fixme: do we need force?
4598 my $drive = parse_drive($opt, $value);
4600 if ($conf->{$opt}) {
4602 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4604 my $media = $drive->{media} || 'disk
';
4605 my $oldmedia = $old_drive->{media} || 'disk
';
4606 die "unable to change media type\n" if $media ne $oldmedia;
4608 if (!drive_is_cdrom($old_drive)) {
4610 if ($drive->{file} ne $old_drive->{file}) {
4612 die "skip\n" if !$hotplug;
4614 # unplug and register as unused
4615 vm_deviceunplug($vmid, $conf, $opt);
4616 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4619 # update existing disk
4621 # skip non hotpluggable value
4622 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4623 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4624 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4625 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4630 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4631 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4632 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4633 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4634 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4635 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4636 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4637 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4638 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4639 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4640 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4641 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4642 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4643 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4644 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4645 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4646 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4647 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4649 qemu_block_set_io_throttle($vmid,"drive-$opt",
4650 ($drive->{mbps} || 0)*1024*1024,
4651 ($drive->{mbps_rd} || 0)*1024*1024,
4652 ($drive->{mbps_wr} || 0)*1024*1024,
4653 $drive->{iops} || 0,
4654 $drive->{iops_rd} || 0,
4655 $drive->{iops_wr} || 0,
4656 ($drive->{mbps_max} || 0)*1024*1024,
4657 ($drive->{mbps_rd_max} || 0)*1024*1024,
4658 ($drive->{mbps_wr_max} || 0)*1024*1024,
4659 $drive->{iops_max} || 0,
4660 $drive->{iops_rd_max} || 0,
4661 $drive->{iops_wr_max} || 0,
4662 $drive->{bps_max_length} || 1,
4663 $drive->{bps_rd_max_length} || 1,
4664 $drive->{bps_wr_max_length} || 1,
4665 $drive->{iops_max_length} || 1,
4666 $drive->{iops_rd_max_length} || 1,
4667 $drive->{iops_wr_max_length} || 1);
4676 if ($drive->{file} eq 'none
') {
4677 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4679 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4680 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4681 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4689 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4691 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4692 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4696 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4697 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4699 PVE::QemuConfig->lock_config($vmid, sub {
4700 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4702 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4704 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4706 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4708 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4709 vmconfig_apply_pending($vmid, $conf, $storecfg);
4710 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4713 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4715 my $defaults = load_defaults();
4717 # set environment variable useful inside network script
4718 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4720 my $local_volumes = {};
4722 if ($targetstorage) {
4723 foreach_drive($conf, sub {
4724 my ($ds, $drive) = @_;
4726 return if drive_is_cdrom($drive);
4728 my $volid = $drive->{file};
4732 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4734 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4735 return if $scfg->{shared};
4736 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4741 foreach my $opt (sort keys %$local_volumes) {
4743 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4744 my $drive = parse_drive($opt, $conf->{$opt});
4746 #if remote storage is specified, use default format
4747 if ($targetstorage && $targetstorage ne "1") {
4748 $storeid = $targetstorage;
4749 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4750 $format = $defFormat;
4752 #else we use same format than original
4753 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4754 $format = qemu_img_format($scfg, $volid);
4757 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4758 my $newdrive = $drive;
4759 $newdrive->{format} = $format;
4760 $newdrive->{file} = $newvolid;
4761 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4762 $local_volumes->{$opt} = $drivestr;
4763 #pass drive to conf for command line
4764 $conf->{$opt} = $drivestr;
4768 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4770 my $migrate_port = 0;
4773 if ($statefile eq 'tcp
') {
4774 my $localip = "localhost";
4775 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4776 my $nodename = PVE::INotify::nodename();
4778 if (!defined($migration_type)) {
4779 if (defined($datacenterconf->{migration}->{type})) {
4780 $migration_type = $datacenterconf->{migration}->{type};
4782 $migration_type = 'secure
';
4786 if ($migration_type eq 'insecure
') {
4787 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4788 if ($migrate_network_addr) {
4789 $localip = $migrate_network_addr;
4791 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4794 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4797 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4798 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4799 $migrate_uri = "tcp:${localip}:${migrate_port}";
4800 push @$cmd, '-incoming
', $migrate_uri;
4803 } elsif ($statefile eq 'unix
') {
4804 # should be default for secure migrations as a ssh TCP forward
4805 # tunnel is not deterministic reliable ready and fails regurarly
4806 # to set up in time, so use UNIX socket forwards
4807 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4808 unlink $socket_addr;
4810 $migrate_uri = "unix:$socket_addr";
4812 push @$cmd, '-incoming
', $migrate_uri;
4816 push @$cmd, '-loadstate
', $statefile;
4823 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4824 my $d = parse_hostpci($conf->{"hostpci$i"});
4826 my $pcidevices = $d->{pciid};
4827 foreach my $pcidevice (@$pcidevices) {
4828 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4830 my $info = pci_device_info("0000:$pciid");
4831 die "IOMMU not present\n" if !check_iommu_support();
4832 die "no pci device info for device '$pciid'\n" if !$info;
4833 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4834 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4838 PVE::Storage::activate_volumes($storecfg, $vollist);
4840 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4842 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4843 eval { run_command($cmd); };
4846 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4847 : $defaults->{cpuunits};
4849 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4850 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4853 Slice => 'qemu
.slice
',
4855 CPUShares => $cpuunits
4858 if (my $cpulimit = $conf->{cpulimit}) {
4859 $properties{CPUQuota} = int($cpulimit * 100);
4861 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4863 if ($conf->{hugepages}) {
4866 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4867 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4869 PVE::QemuServer::Memory::hugepages_mount();
4870 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4873 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4874 run_command($cmd, %run_params);
4878 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4882 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4884 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4888 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4889 run_command($cmd, %run_params);
4894 # deactivate volumes if start fails
4895 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4896 die "start failed: $err";
4899 print "migration listens on $migrate_uri\n" if $migrate_uri;
4901 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4902 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4906 #start nbd server for storage migration
4907 if ($targetstorage) {
4908 my $nodename = PVE::INotify::nodename();
4909 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4910 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4911 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4912 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4914 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4916 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4918 foreach my $opt (sort keys %$local_volumes) {
4919 my $volid = $local_volumes->{$opt};
4920 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4921 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4922 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4926 if ($migratedfrom) {
4928 set_migration_caps($vmid);
4933 print "spice listens on port $spice_port\n";
4934 if ($spice_ticket) {
4935 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4936 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4941 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4942 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4943 if $conf->{balloon};
4946 foreach my $opt (keys %$conf) {
4947 next if $opt !~ m/^net\d+$/;
4948 my $nicconf = parse_net($conf->{$opt});
4949 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4953 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4954 path => "machine/peripheral/balloon0",
4955 property => "guest-stats-polling-interval",
4956 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4962 my ($vmid, $execute, %params) = @_;
4964 my $cmd = { execute => $execute, arguments => \%params };
4965 vm_qmp_command($vmid, $cmd);
4968 sub vm_mon_cmd_nocheck {
4969 my ($vmid, $execute, %params) = @_;
4971 my $cmd = { execute => $execute, arguments => \%params };
4972 vm_qmp_command($vmid, $cmd, 1);
4975 sub vm_qmp_command {
4976 my ($vmid, $cmd, $nocheck) = @_;
4981 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4982 $timeout = $cmd->{arguments}->{timeout};
4983 delete $cmd->{arguments}->{timeout};
4987 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4988 my $sname = qmp_socket($vmid);
4989 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4990 my $qmpclient = PVE::QMPClient->new();
4992 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4993 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
4994 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
4995 if scalar(%{$cmd->{arguments}});
4996 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
4998 die "unable to
open monitor
socket\n";
5002 syslog("err
", "VM
$vmid qmp command failed
- $err");
5009 sub vm_human_monitor_command {
5010 my ($vmid, $cmdline) = @_;
5015 execute => 'human-monitor-command',
5016 arguments => { 'command-line' => $cmdline},
5019 return vm_qmp_command($vmid, $cmd);
5022 sub vm_commandline {
5023 my ($storecfg, $vmid) = @_;
5025 my $conf = PVE::QemuConfig->load_config($vmid);
5027 my $defaults = load_defaults();
5029 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5031 return PVE::Tools::cmd2string($cmd);
5035 my ($vmid, $skiplock) = @_;
5037 PVE::QemuConfig->lock_config($vmid, sub {
5039 my $conf = PVE::QemuConfig->load_config($vmid);
5041 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5043 vm_mon_cmd($vmid, "system_reset
");
5047 sub get_vm_volumes {
5051 foreach_volid($conf, sub {
5052 my ($volid, $attr) = @_;
5054 return if $volid =~ m|^/|;
5056 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5059 push @$vollist, $volid;
5065 sub vm_stop_cleanup {
5066 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5071 my $vollist = get_vm_volumes($conf);
5072 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5075 foreach my $ext (qw(mon qmp pid vnc qga)) {
5076 unlink "/var/run/qemu-server/${vmid}.$ext";
5079 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5081 warn $@ if $@; # avoid errors - just warn
5084 # Note: use $nockeck to skip tests if VM configuration file exists.
5085 # We need that when migration VMs to other nodes (files already moved)
5086 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5088 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5090 $force = 1 if !defined($force) && !$shutdown;
5093 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5094 kill 15, $pid if $pid;
5095 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5096 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5100 PVE
::QemuConfig-
>lock_config($vmid, sub {
5102 my $pid = check_running
($vmid, $nocheck);
5107 $conf = PVE
::QemuConfig-
>load_config($vmid);
5108 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5109 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5110 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5111 $timeout = $opts->{down
} if $opts->{down
};
5115 $timeout = 60 if !defined($timeout);
5119 if (defined($conf) && $conf->{agent
}) {
5120 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5122 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5125 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5132 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5137 if ($count >= $timeout) {
5139 warn "VM still running - terminating now with SIGTERM\n";
5142 die "VM quit/powerdown failed - got timeout\n";
5145 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5150 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5153 die "VM quit/powerdown failed\n";
5161 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5166 if ($count >= $timeout) {
5167 warn "VM still running - terminating now with SIGKILL\n";
5172 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5177 my ($vmid, $skiplock) = @_;
5179 PVE
::QemuConfig-
>lock_config($vmid, sub {
5181 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5183 PVE
::QemuConfig-
>check_lock($conf)
5184 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5186 vm_mon_cmd
($vmid, "stop");
5191 my ($vmid, $skiplock, $nocheck) = @_;
5193 PVE
::QemuConfig-
>lock_config($vmid, sub {
5197 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5199 PVE
::QemuConfig-
>check_lock($conf)
5200 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5202 vm_mon_cmd
($vmid, "cont");
5205 vm_mon_cmd_nocheck
($vmid, "cont");
5211 my ($vmid, $skiplock, $key) = @_;
5213 PVE
::QemuConfig-
>lock_config($vmid, sub {
5215 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5217 # there is no qmp command, so we use the human monitor command
5218 vm_human_monitor_command
($vmid, "sendkey $key");
5223 my ($storecfg, $vmid, $skiplock) = @_;
5225 PVE
::QemuConfig-
>lock_config($vmid, sub {
5227 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5229 if (!check_running
($vmid)) {
5230 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5232 die "VM $vmid is running - destroy failed\n";
5240 my ($filename, $buf) = @_;
5242 my $fh = IO
::File-
>new($filename, "w");
5243 return undef if !$fh;
5245 my $res = print $fh $buf;
5252 sub pci_device_info
{
5257 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5258 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5260 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5261 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5263 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5264 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5266 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5267 return undef if !defined($product) || $product !~ s/^0x//;
5272 product
=> $product,
5278 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5287 my $name = $dev->{name
};
5289 my $fn = "$pcisysfs/devices/$name/reset";
5291 return file_write
($fn, "1");
5294 sub pci_dev_bind_to_vfio
{
5297 my $name = $dev->{name
};
5299 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5301 if (!-d
$vfio_basedir) {
5302 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5304 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5306 my $testdir = "$vfio_basedir/$name";
5307 return 1 if -d
$testdir;
5309 my $data = "$dev->{vendor} $dev->{product}";
5310 return undef if !file_write
("$vfio_basedir/new_id", $data);
5312 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5313 if (!file_write
($fn, $name)) {
5314 return undef if -f
$fn;
5317 $fn = "$vfio_basedir/bind";
5318 if (! -d
$testdir) {
5319 return undef if !file_write
($fn, $name);
5325 sub pci_dev_group_bind_to_vfio
{
5328 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5330 if (!-d
$vfio_basedir) {
5331 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5333 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5335 # get IOMMU group devices
5336 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5337 my @devs = grep /^0000:/, readdir($D);
5340 foreach my $pciid (@devs) {
5341 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5343 # pci bridges, switches or root ports are not supported
5344 # they have a pci_bus subdirectory so skip them
5345 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5347 my $info = pci_device_info
($1);
5348 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5354 # vzdump restore implementaion
5356 sub tar_archive_read_firstfile
{
5357 my $archive = shift;
5359 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5361 # try to detect archive type first
5362 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5363 die "unable to open file '$archive'\n";
5364 my $firstfile = <$fh>;
5368 die "ERROR: archive contaions no data\n" if !$firstfile;
5374 sub tar_restore_cleanup
{
5375 my ($storecfg, $statfile) = @_;
5377 print STDERR
"starting cleanup\n";
5379 if (my $fd = IO
::File-
>new($statfile, "r")) {
5380 while (defined(my $line = <$fd>)) {
5381 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5384 if ($volid =~ m
|^/|) {
5385 unlink $volid || die 'unlink failed\n';
5387 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5389 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5391 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5393 print STDERR
"unable to parse line in statfile - $line";
5400 sub restore_archive
{
5401 my ($archive, $vmid, $user, $opts) = @_;
5403 my $format = $opts->{format
};
5406 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5407 $format = 'tar' if !$format;
5409 } elsif ($archive =~ m/\.tar$/) {
5410 $format = 'tar' if !$format;
5411 } elsif ($archive =~ m/.tar.lzo$/) {
5412 $format = 'tar' if !$format;
5414 } elsif ($archive =~ m/\.vma$/) {
5415 $format = 'vma' if !$format;
5416 } elsif ($archive =~ m/\.vma\.gz$/) {
5417 $format = 'vma' if !$format;
5419 } elsif ($archive =~ m/\.vma\.lzo$/) {
5420 $format = 'vma' if !$format;
5423 $format = 'vma' if !$format; # default
5426 # try to detect archive format
5427 if ($format eq 'tar') {
5428 return restore_tar_archive
($archive, $vmid, $user, $opts);
5430 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5434 sub restore_update_config_line
{
5435 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5437 return if $line =~ m/^\#qmdump\#/;
5438 return if $line =~ m/^\#vzdump\#/;
5439 return if $line =~ m/^lock:/;
5440 return if $line =~ m/^unused\d+:/;
5441 return if $line =~ m/^parent:/;
5442 return if $line =~ m/^template:/; # restored VM is never a template
5444 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5445 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5446 # try to convert old 1.X settings
5447 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5448 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5449 my ($model, $macaddr) = split(/\=/, $devconfig);
5450 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5453 bridge
=> "vmbr$ind",
5454 macaddr
=> $macaddr,
5456 my $netstr = print_net
($net);
5458 print $outfd "net$cookie->{netcount}: $netstr\n";
5459 $cookie->{netcount
}++;
5461 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5462 my ($id, $netstr) = ($1, $2);
5463 my $net = parse_net
($netstr);
5464 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5465 $netstr = print_net
($net);
5466 print $outfd "$id: $netstr\n";
5467 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5470 my $di = parse_drive
($virtdev, $value);
5471 if (defined($di->{backup
}) && !$di->{backup
}) {
5472 print $outfd "#$line";
5473 } elsif ($map->{$virtdev}) {
5474 delete $di->{format
}; # format can change on restore
5475 $di->{file
} = $map->{$virtdev};
5476 $value = print_drive
($vmid, $di);
5477 print $outfd "$virtdev: $value\n";
5481 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5482 my ($uuid, $uuid_str);
5483 UUID
::generate
($uuid);
5484 UUID
::unparse
($uuid, $uuid_str);
5485 my $smbios1 = parse_smbios1
($2);
5486 $smbios1->{uuid
} = $uuid_str;
5487 print $outfd $1.print_smbios1
($smbios1)."\n";
5494 my ($cfg, $vmid) = @_;
5496 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5498 my $volid_hash = {};
5499 foreach my $storeid (keys %$info) {
5500 foreach my $item (@{$info->{$storeid}}) {
5501 next if !($item->{volid
} && $item->{size
});
5502 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5503 $volid_hash->{$item->{volid
}} = $item;
5510 sub is_volume_in_use
{
5511 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5513 my $path = PVE
::Storage
::path
($storecfg, $volid);
5515 my $scan_config = sub {
5516 my ($cref, $snapname) = @_;
5518 foreach my $key (keys %$cref) {
5519 my $value = $cref->{$key};
5520 if (is_valid_drivename
($key)) {
5521 next if $skip_drive && $key eq $skip_drive;
5522 my $drive = parse_drive
($key, $value);
5523 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5524 return 1 if $volid eq $drive->{file
};
5525 if ($drive->{file
} =~ m!^/!) {
5526 return 1 if $drive->{file
} eq $path;
5528 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5530 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5532 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5540 return 1 if &$scan_config($conf);
5544 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5545 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5551 sub update_disksize
{
5552 my ($vmid, $conf, $volid_hash) = @_;
5556 # used and unused disks
5557 my $referenced = {};
5559 # Note: it is allowed to define multiple storages with same path (alias), so
5560 # we need to check both 'volid' and real 'path' (two different volid can point
5561 # to the same path).
5563 my $referencedpath = {};
5566 foreach my $opt (keys %$conf) {
5567 if (is_valid_drivename
($opt)) {
5568 my $drive = parse_drive
($opt, $conf->{$opt});
5569 my $volid = $drive->{file
};
5572 $referenced->{$volid} = 1;
5573 if ($volid_hash->{$volid} &&
5574 (my $path = $volid_hash->{$volid}->{path
})) {
5575 $referencedpath->{$path} = 1;
5578 next if drive_is_cdrom
($drive);
5579 next if !$volid_hash->{$volid};
5581 $drive->{size
} = $volid_hash->{$volid}->{size
};
5582 my $new = print_drive
($vmid, $drive);
5583 if ($new ne $conf->{$opt}) {
5585 $conf->{$opt} = $new;
5590 # remove 'unusedX' entry if volume is used
5591 foreach my $opt (keys %$conf) {
5592 next if $opt !~ m/^unused\d+$/;
5593 my $volid = $conf->{$opt};
5594 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5595 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5597 delete $conf->{$opt};
5600 $referenced->{$volid} = 1;
5601 $referencedpath->{$path} = 1 if $path;
5604 foreach my $volid (sort keys %$volid_hash) {
5605 next if $volid =~ m/vm-$vmid-state-/;
5606 next if $referenced->{$volid};
5607 my $path = $volid_hash->{$volid}->{path
};
5608 next if !$path; # just to be sure
5609 next if $referencedpath->{$path};
5611 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5612 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5619 my ($vmid, $nolock) = @_;
5621 my $cfg = PVE
::Storage
::config
();
5623 my $volid_hash = scan_volids
($cfg, $vmid);
5625 my $updatefn = sub {
5628 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5630 PVE
::QemuConfig-
>check_lock($conf);
5633 foreach my $volid (keys %$volid_hash) {
5634 my $info = $volid_hash->{$volid};
5635 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5638 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5640 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5643 if (defined($vmid)) {
5647 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5650 my $vmlist = config_list
();
5651 foreach my $vmid (keys %$vmlist) {
5655 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5661 sub restore_vma_archive
{
5662 my ($archive, $vmid, $user, $opts, $comp) = @_;
5664 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5665 my $readfrom = $archive;
5670 my $qarchive = PVE
::Tools
::shellquote
($archive);
5671 if ($comp eq 'gzip') {
5672 $uncomp = "zcat $qarchive|";
5673 } elsif ($comp eq 'lzop') {
5674 $uncomp = "lzop -d -c $qarchive|";
5676 die "unknown compression method '$comp'\n";
5681 my $tmpdir = "/var/tmp/vzdumptmp$$";
5684 # disable interrupts (always do cleanups)
5688 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5690 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5691 POSIX
::mkfifo
($mapfifo, 0600);
5694 my $openfifo = sub {
5695 open($fifofh, '>', $mapfifo) || die $!;
5698 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5705 my $rpcenv = PVE
::RPCEnvironment
::get
();
5707 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5708 my $tmpfn = "$conffile.$$.tmp";
5710 # Note: $oldconf is undef if VM does not exists
5711 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5712 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5714 my $print_devmap = sub {
5715 my $virtdev_hash = {};
5717 my $cfgfn = "$tmpdir/qemu-server.conf";
5719 # we can read the config - that is already extracted
5720 my $fh = IO
::File-
>new($cfgfn, "r") ||
5721 "unable to read qemu-server.conf - $!\n";
5723 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5725 my $pve_firewall_dir = '/etc/pve/firewall';
5726 mkdir $pve_firewall_dir; # make sure the dir exists
5727 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5730 while (defined(my $line = <$fh>)) {
5731 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5732 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5733 die "archive does not contain data for drive '$virtdev'\n"
5734 if !$devinfo->{$devname};
5735 if (defined($opts->{storage
})) {
5736 $storeid = $opts->{storage
} || 'local';
5737 } elsif (!$storeid) {
5740 $format = 'raw' if !$format;
5741 $devinfo->{$devname}->{devname
} = $devname;
5742 $devinfo->{$devname}->{virtdev
} = $virtdev;
5743 $devinfo->{$devname}->{format
} = $format;
5744 $devinfo->{$devname}->{storeid
} = $storeid;
5746 # check permission on storage
5747 my $pool = $opts->{pool
}; # todo: do we need that?
5748 if ($user ne 'root@pam') {
5749 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5752 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5756 foreach my $devname (keys %$devinfo) {
5757 die "found no device mapping information for device '$devname'\n"
5758 if !$devinfo->{$devname}->{virtdev
};
5761 my $cfg = PVE
::Storage
::config
();
5763 # create empty/temp config
5765 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5766 foreach_drive
($oldconf, sub {
5767 my ($ds, $drive) = @_;
5769 return if drive_is_cdrom
($drive);
5771 my $volid = $drive->{file
};
5773 return if !$volid || $volid =~ m
|^/|;
5775 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5776 return if !$path || !$owner || ($owner != $vmid);
5778 # Note: only delete disk we want to restore
5779 # other volumes will become unused
5780 if ($virtdev_hash->{$ds}) {
5781 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5788 # delete vmstate files
5789 # since after the restore we have no snapshots anymore
5790 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5791 my $snap = $oldconf->{snapshots
}->{$snapname};
5792 if ($snap->{vmstate
}) {
5793 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5802 foreach my $virtdev (sort keys %$virtdev_hash) {
5803 my $d = $virtdev_hash->{$virtdev};
5804 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5805 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5807 # test if requested format is supported
5808 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5809 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5810 $d->{format
} = $defFormat if !$supported;
5812 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5813 $d->{format
}, undef, $alloc_size);
5814 print STDERR
"new volume ID is '$volid'\n";
5815 $d->{volid
} = $volid;
5816 my $path = PVE
::Storage
::path
($cfg, $volid);
5818 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5820 my $write_zeros = 1;
5821 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5825 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5827 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5828 $map->{$virtdev} = $volid;
5831 $fh->seek(0, 0) || die "seek failed - $!\n";
5833 my $outfd = new IO
::File
($tmpfn, "w") ||
5834 die "unable to write config for VM $vmid\n";
5836 my $cookie = { netcount
=> 0 };
5837 while (defined(my $line = <$fh>)) {
5838 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5851 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5852 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5854 $oldtimeout = alarm($timeout);
5861 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5862 my ($dev_id, $size, $devname) = ($1, $2, $3);
5863 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5864 } elsif ($line =~ m/^CTIME: /) {
5865 # we correctly received the vma config, so we can disable
5866 # the timeout now for disk allocation (set to 10 minutes, so
5867 # that we always timeout if something goes wrong)
5870 print $fifofh "done\n";
5871 my $tmp = $oldtimeout || 0;
5872 $oldtimeout = undef;
5878 print "restore vma archive: $cmd\n";
5879 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5883 alarm($oldtimeout) if $oldtimeout;
5886 foreach my $devname (keys %$devinfo) {
5887 my $volid = $devinfo->{$devname}->{volid
};
5888 push @$vollist, $volid if $volid;
5891 my $cfg = PVE
::Storage
::config
();
5892 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5900 foreach my $devname (keys %$devinfo) {
5901 my $volid = $devinfo->{$devname}->{volid
};
5904 if ($volid =~ m
|^/|) {
5905 unlink $volid || die 'unlink failed\n';
5907 PVE
::Storage
::vdisk_free
($cfg, $volid);
5909 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5911 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5918 rename($tmpfn, $conffile) ||
5919 die "unable to commit configuration file '$conffile'\n";
5921 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5923 eval { rescan
($vmid, 1); };
5927 sub restore_tar_archive
{
5928 my ($archive, $vmid, $user, $opts) = @_;
5930 if ($archive ne '-') {
5931 my $firstfile = tar_archive_read_firstfile
($archive);
5932 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5933 if $firstfile ne 'qemu-server.conf';
5936 my $storecfg = PVE
::Storage
::config
();
5938 # destroy existing data - keep empty config
5939 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5940 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5942 my $tocmd = "/usr/lib/qemu-server/qmextract";
5944 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5945 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5946 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5947 $tocmd .= ' --info' if $opts->{info
};
5949 # tar option "xf" does not autodetect compression when read from STDIN,
5950 # so we pipe to zcat
5951 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5952 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5954 my $tmpdir = "/var/tmp/vzdumptmp$$";
5957 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5958 local $ENV{VZDUMP_VMID
} = $vmid;
5959 local $ENV{VZDUMP_USER
} = $user;
5961 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5962 my $tmpfn = "$conffile.$$.tmp";
5964 # disable interrupts (always do cleanups)
5968 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
5976 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5978 if ($archive eq '-') {
5979 print "extracting archive from STDIN\n";
5980 run_command
($cmd, input
=> "<&STDIN");
5982 print "extracting archive '$archive'\n";
5986 return if $opts->{info
};
5990 my $statfile = "$tmpdir/qmrestore.stat";
5991 if (my $fd = IO
::File-
>new($statfile, "r")) {
5992 while (defined (my $line = <$fd>)) {
5993 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5994 $map->{$1} = $2 if $1;
5996 print STDERR
"unable to parse line in statfile - $line\n";
6002 my $confsrc = "$tmpdir/qemu-server.conf";
6004 my $srcfd = new IO
::File
($confsrc, "r") ||
6005 die "unable to open file '$confsrc'\n";
6007 my $outfd = new IO
::File
($tmpfn, "w") ||
6008 die "unable to write config for VM $vmid\n";
6010 my $cookie = { netcount
=> 0 };
6011 while (defined (my $line = <$srcfd>)) {
6012 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6024 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6031 rename $tmpfn, $conffile ||
6032 die "unable to commit configuration file '$conffile'\n";
6034 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6036 eval { rescan
($vmid, 1); };
6040 sub foreach_storage_used_by_vm
{
6041 my ($conf, $func) = @_;
6045 foreach_drive
($conf, sub {
6046 my ($ds, $drive) = @_;
6047 return if drive_is_cdrom
($drive);
6049 my $volid = $drive->{file
};
6051 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6052 $sidhash->{$sid} = $sid if $sid;
6055 foreach my $sid (sort keys %$sidhash) {
6060 sub do_snapshots_with_qemu
{
6061 my ($storecfg, $volid) = @_;
6063 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6065 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6066 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6070 if ($volid =~ m/\.(qcow2|qed)$/){
6077 sub qga_check_running
{
6080 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6082 warn "Qemu Guest Agent is not running - $@";
6088 sub template_create
{
6089 my ($vmid, $conf, $disk) = @_;
6091 my $storecfg = PVE
::Storage
::config
();
6093 foreach_drive
($conf, sub {
6094 my ($ds, $drive) = @_;
6096 return if drive_is_cdrom
($drive);
6097 return if $disk && $ds ne $disk;
6099 my $volid = $drive->{file
};
6100 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6102 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6103 $drive->{file
} = $voliddst;
6104 $conf->{$ds} = print_drive
($vmid, $drive);
6105 PVE
::QemuConfig-
>write_config($vmid, $conf);
6109 sub qemu_img_convert
{
6110 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6112 my $storecfg = PVE
::Storage
::config
();
6113 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6114 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6116 if ($src_storeid && $dst_storeid) {
6118 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6120 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6121 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6123 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6124 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6126 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6127 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6130 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6131 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6132 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6133 if ($is_zero_initialized) {
6134 push @$cmd, "zeroinit:$dst_path";
6136 push @$cmd, $dst_path;
6141 if($line =~ m/\((\S+)\/100\
%\)/){
6143 my $transferred = int($size * $percent / 100);
6144 my $remaining = $size - $transferred;
6146 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6151 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6153 die "copy failed: $err" if $err;
6157 sub qemu_img_format
{
6158 my ($scfg, $volname) = @_;
6160 if ($scfg->{path
} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
6167 sub qemu_drive_mirror
{
6168 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6170 $jobs = {} if !$jobs;
6174 $jobs->{"drive-$drive"} = {};
6176 if ($dst_volid =~ /^nbd:/) {
6177 $qemu_target = $dst_volid;
6180 my $storecfg = PVE
::Storage
::config
();
6181 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6183 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6185 $format = qemu_img_format
($dst_scfg, $dst_volname);
6187 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6189 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6192 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6193 $opts->{format
} = $format if $format;
6195 print "drive mirror is starting for drive-$drive\n";
6197 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6200 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6201 die "mirroring error: $err";
6204 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6207 sub qemu_drive_mirror_monitor
{
6208 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6211 my $err_complete = 0;
6214 die "storage migration timed out\n" if $err_complete > 300;
6216 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6218 my $running_mirror_jobs = {};
6219 foreach my $stat (@$stats) {
6220 next if $stat->{type
} ne 'mirror';
6221 $running_mirror_jobs->{$stat->{device
}} = $stat;
6224 my $readycounter = 0;
6226 foreach my $job (keys %$jobs) {
6228 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6229 print "$job : finished\n";
6230 delete $jobs->{$job};
6234 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6236 my $busy = $running_mirror_jobs->{$job}->{busy
};
6237 my $ready = $running_mirror_jobs->{$job}->{ready
};
6238 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6239 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6240 my $remaining = $total - $transferred;
6241 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6243 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6246 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6249 last if scalar(keys %$jobs) == 0;
6251 if ($readycounter == scalar(keys %$jobs)) {
6252 print "all mirroring jobs are ready \n";
6253 last if $skipcomplete; #do the complete later
6255 if ($vmiddst && $vmiddst != $vmid) {
6256 my $agent_running = $qga && qga_check_running
($vmid);
6257 if ($agent_running) {
6258 print "freeze filesystem\n";
6259 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6261 print "suspend vm\n";
6262 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6265 # if we clone a disk for a new target vm, we don't switch the disk
6266 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6268 if ($agent_running) {
6269 print "unfreeze filesystem\n";
6270 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6272 print "resume vm\n";
6273 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6279 foreach my $job (keys %$jobs) {
6280 # try to switch the disk if source and destination are on the same guest
6281 print "$job: Completing block job...\n";
6283 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6284 if ($@ =~ m/cannot be completed/) {
6285 print "$job: Block job cannot be completed, try again.\n";
6288 print "$job: Completed successfully.\n";
6289 $jobs->{$job}->{complete
} = 1;
6300 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6301 die "mirroring error: $err";
6306 sub qemu_blockjobs_cancel
{
6307 my ($vmid, $jobs) = @_;
6309 foreach my $job (keys %$jobs) {
6310 print "$job: Cancelling block job\n";
6311 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6312 $jobs->{$job}->{cancel
} = 1;
6316 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6318 my $running_jobs = {};
6319 foreach my $stat (@$stats) {
6320 $running_jobs->{$stat->{device
}} = $stat;
6323 foreach my $job (keys %$jobs) {
6325 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6326 print "$job: Done.\n";
6327 delete $jobs->{$job};
6331 last if scalar(keys %$jobs) == 0;
6338 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6339 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6344 print "create linked clone of drive $drivename ($drive->{file})\n";
6345 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6346 push @$newvollist, $newvolid;
6349 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6350 $storeid = $storage if $storage;
6352 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6353 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6355 print "create full clone of drive $drivename ($drive->{file})\n";
6356 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, undef, ($size/1024));
6357 push @$newvollist, $newvolid;
6359 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6361 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6362 if (!$running || $snapname) {
6363 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6366 my $kvmver = get_running_qemu_version
($vmid);
6367 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6368 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6369 if $drive->{iothread
};
6372 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6376 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6379 $disk->{format
} = undef;
6380 $disk->{file
} = $newvolid;
6381 $disk->{size
} = $size;
6386 # this only works if VM is running
6387 sub get_current_qemu_machine
{
6390 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6391 my $res = vm_qmp_command
($vmid, $cmd);
6393 my ($current, $default);
6394 foreach my $e (@$res) {
6395 $default = $e->{name
} if $e->{'is-default'};
6396 $current = $e->{name
} if $e->{'is-current'};
6399 # fallback to the default machine if current is not supported by qemu
6400 return $current || $default || 'pc';
6403 sub get_running_qemu_version
{
6405 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6406 my $res = vm_qmp_command
($vmid, $cmd);
6407 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6410 sub qemu_machine_feature_enabled
{
6411 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6416 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6418 $current_major = $3;
6419 $current_minor = $4;
6421 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6423 $current_major = $1;
6424 $current_minor = $2;
6427 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6432 sub qemu_machine_pxe
{
6433 my ($vmid, $conf, $machine) = @_;
6435 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6437 foreach my $opt (keys %$conf) {
6438 next if $opt !~ m/^net(\d+)$/;
6439 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6441 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6442 return $machine.".pxe" if $romfile =~ m/pxe/;
6449 sub qemu_use_old_bios_files
{
6450 my ($machine_type) = @_;
6452 return if !$machine_type;
6454 my $use_old_bios_files = undef;
6456 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6458 $use_old_bios_files = 1;
6460 my $kvmver = kvm_user_version
();
6461 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6462 # load new efi bios files on migration. So this hack is required to allow
6463 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6464 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6465 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6468 return ($use_old_bios_files, $machine_type);
6471 sub create_efidisk
{
6472 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6474 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6476 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6477 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6478 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6480 my $path = PVE
::Storage
::path
($storecfg, $volid);
6482 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6484 die "Copying EFI vars image failed: $@" if $@;
6486 return ($volid, $vars_size);
6493 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6494 my (undef, $id, $function) = @_;
6495 my $res = { id
=> $id, function
=> $function};
6496 push @{$devices->{$id}}, $res;
6499 # Entries should be sorted by functions.
6500 foreach my $id (keys %$devices) {
6501 my $dev = $devices->{$id};
6502 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6508 sub vm_iothreads_list
{
6511 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6514 foreach my $iothread (@$res) {
6515 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6522 my ($conf, $drive) = @_;
6526 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6528 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6534 my $controller = int($drive->{index} / $maxdev);
6535 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6537 return ($maxdev, $controller, $controller_prefix);
6540 sub add_hyperv_enlightenments
{
6541 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6543 return if $winversion < 6;
6544 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6546 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6548 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6549 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6550 push @$cpuFlags , 'hv_vapic';
6551 push @$cpuFlags , 'hv_time';
6553 push @$cpuFlags , 'hv_spinlocks=0xffff';
6556 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6557 push @$cpuFlags , 'hv_reset';
6558 push @$cpuFlags , 'hv_vpindex';
6559 push @$cpuFlags , 'hv_runtime';
6562 if ($winversion >= 7) {
6563 push @$cpuFlags , 'hv_relaxed';
6567 sub windows_version
{
6570 return 0 if !$ostype;
6574 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6576 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6578 } elsif ($ostype =~ m/^win(\d+)$/) {
6585 sub resolve_dst_disk_format
{
6586 my ($storecfg, $storeid, $src_volname, $format) = @_;
6587 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6590 # if no target format is specified, use the source disk format as hint
6592 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6593 $format = qemu_img_format
($scfg, $src_volname);
6599 # test if requested format is supported - else use default
6600 my $supported = grep { $_ eq $format } @$validFormats;
6601 $format = $defFormat if !$supported;
6605 sub resolve_first_disk
{
6607 my @disks = PVE
::QemuServer
::valid_drive_names
();
6609 foreach my $ds (reverse @disks) {
6610 next if !$conf->{$ds};
6611 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6612 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6618 sub generate_smbios1_uuid
{
6619 my ($uuid, $uuid_str);
6620 UUID
::generate
($uuid);
6621 UUID
::unparse
($uuid, $uuid_str);
6622 return "uuid=$uuid_str";
6625 # bash completion helper
6627 sub complete_backup_archives
{
6628 my ($cmdname, $pname, $cvalue) = @_;
6630 my $cfg = PVE
::Storage
::config
();
6634 if ($cvalue =~ m/^([^:]+):/) {
6638 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6641 foreach my $id (keys %$data) {
6642 foreach my $item (@{$data->{$id}}) {
6643 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6644 push @$res, $item->{volid
} if defined($item->{volid
});
6651 my $complete_vmid_full = sub {
6654 my $idlist = vmstatus
();
6658 foreach my $id (keys %$idlist) {
6659 my $d = $idlist->{$id};
6660 if (defined($running)) {
6661 next if $d->{template
};
6662 next if $running && $d->{status
} ne 'running';
6663 next if !$running && $d->{status
} eq 'running';
6672 return &$complete_vmid_full();
6675 sub complete_vmid_stopped
{
6676 return &$complete_vmid_full(0);
6679 sub complete_vmid_running
{
6680 return &$complete_vmid_full(1);
6683 sub complete_storage
{
6685 my $cfg = PVE
::Storage
::config
();
6686 my $ids = $cfg->{ids
};
6689 foreach my $sid (keys %$ids) {
6690 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6691 next if !$ids->{$sid}->{content
}->{images
};