1 package PVE
::QemuServer
;
22 use Storable
qw(dclone);
23 use PVE
::Exception
qw(raise raise_param_exc);
25 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
26 use PVE
::JSONSchema
qw(get_standard_option);
27 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
32 use PVE
::RPCEnvironment
;
33 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr);
34 use PVE
::QemuServer
::Memory
;
35 use PVE
::QemuServer
::USB
qw(parse_usb_device);
36 use PVE
::QemuServer
::Cloudinit
;
37 use Time
::HiRes
qw(gettimeofday);
38 use File
::Copy
qw(copy);
41 my $OVMF_CODE = '/usr/share/kvm/OVMF_CODE-pure-efi.fd';
42 my $OVMF_VARS = '/usr/share/kvm/OVMF_VARS-pure-efi.fd';
44 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
46 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
48 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
50 # Note about locking: we use flock on the config file protect
51 # against concurent actions.
52 # Aditionaly, we have a 'lock' setting in the config file. This
53 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
54 # allowed when such lock is set. But you can ignore this kind of
55 # lock with the --skiplock flag.
57 cfs_register_file
('/qemu-server/',
61 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
62 description
=> "Some command save/restore state from this location.",
68 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
69 description
=> "The name of the snapshot.",
70 type
=> 'string', format
=> 'pve-configid',
74 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
76 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
77 description
=> "The drive's backing file's data format.",
81 #no warnings 'redefine';
84 my ($controller, $vmid, $option, $value) = @_;
86 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
87 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
91 my $nodename = PVE
::INotify
::nodename
();
93 mkdir "/etc/pve/nodes/$nodename";
94 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
97 my $var_run_tmpdir = "/var/run/qemu-server";
98 mkdir $var_run_tmpdir;
100 my $lock_dir = "/var/lock/qemu-server";
103 my $pcisysfs = "/sys/bus/pci";
105 my $cpu_vendor_list = {
107 486 => 'GenuineIntel',
108 pentium
=> 'GenuineIntel',
109 pentium2
=> 'GenuineIntel',
110 pentium3
=> 'GenuineIntel',
111 coreduo
=> 'GenuineIntel',
112 core2duo
=> 'GenuineIntel',
113 Conroe
=> 'GenuineIntel',
114 Penryn
=> 'GenuineIntel',
115 Nehalem
=> 'GenuineIntel',
116 'Nehalem-IBRS' => 'GenuineIntel',
117 Westmere
=> 'GenuineIntel',
118 'Westmere-IBRS' => 'GenuineIntel',
119 SandyBridge
=> 'GenuineIntel',
120 'SandyBridge-IBRS' => 'GenuineIntel',
121 IvyBridge
=> 'GenuineIntel',
122 'IvyBridge-IBRS' => 'GenuineIntel',
123 Haswell
=> 'GenuineIntel',
124 'Haswell-IBRS' => 'GenuineIntel',
125 'Haswell-noTSX' => 'GenuineIntel',
126 'Haswell-noTSX-IBRS' => 'GenuineIntel',
127 Broadwell
=> 'GenuineIntel',
128 'Broadwell-IBRS' => 'GenuineIntel',
129 'Broadwell-noTSX' => 'GenuineIntel',
130 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
131 'Skylake-Client' => 'GenuineIntel',
132 'Skylake-Client-IBRS' => 'GenuineIntel',
133 'Skylake-Server' => 'GenuineIntel',
134 'Skylake-Server-IBRS' => 'GenuineIntel',
137 athlon
=> 'AuthenticAMD',
138 phenom
=> 'AuthenticAMD',
139 Opteron_G1
=> 'AuthenticAMD',
140 Opteron_G2
=> 'AuthenticAMD',
141 Opteron_G3
=> 'AuthenticAMD',
142 Opteron_G4
=> 'AuthenticAMD',
143 Opteron_G5
=> 'AuthenticAMD',
144 EPYC
=> 'AuthenticAMD',
145 'EPYC-IBPB' => 'AuthenticAMD',
147 # generic types, use vendor from host node
156 my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
160 description
=> "Emulated CPU type.",
162 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
167 description
=> "Do not identify as a KVM virtual machine.",
173 description
=> "List of additional CPU flags separated by ';'."
174 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
175 . " Currently supported flags: 'pcid', 'spec-ctrl'.",
176 format_description
=> '+FLAG[;-FLAG...]',
178 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
187 enum
=> [qw(i6300esb ib700)],
188 description
=> "Watchdog type to emulate.",
189 default => 'i6300esb',
194 enum
=> [qw(reset shutdown poweroff pause debug none)],
195 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
199 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
205 description
=> "Specifies whether a VM will be started during system bootup.",
211 description
=> "Automatic restart after crash (currently ignored).",
216 type
=> 'string', format
=> 'pve-hotplug-features',
217 description
=> "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
218 default => 'network,disk,usb',
223 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
229 description
=> "Lock/unlock the VM.",
230 enum
=> [qw(migrate backup snapshot rollback)],
235 description
=> "Limit of CPU usage.",
236 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
244 description
=> "CPU weight for a VM.",
245 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
253 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
260 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
266 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning",
274 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.".
275 "It should not be necessary to set it.",
276 enum
=> PVE
::Tools
::kvmkeymaplist
(),
281 type
=> 'string', format
=> 'dns-name',
282 description
=> "Set a name for the VM. Only used on the configuration web interface.",
287 description
=> "SCSI controller model",
288 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
294 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
299 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
300 description
=> "Specify guest operating system.",
301 verbose_description
=> <<EODESC,
302 Specify guest operating system. This is used to enable special
303 optimization/features for specific operating systems:
306 other;; unspecified OS
307 wxp;; Microsoft Windows XP
308 w2k;; Microsoft Windows 2000
309 w2k3;; Microsoft Windows 2003
310 w2k8;; Microsoft Windows 2008
311 wvista;; Microsoft Windows Vista
312 win7;; Microsoft Windows 7
313 win8;; Microsoft Windows 8/2012/2012r2
314 win10;; Microsoft Windows 10/2016
315 l24;; Linux 2.4 Kernel
316 l26;; Linux 2.6/3.X Kernel
317 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
323 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
324 pattern
=> '[acdn]{1,4}',
329 type
=> 'string', format
=> 'pve-qm-bootdisk',
330 description
=> "Enable booting from specified disk.",
331 pattern
=> '(ide|sata|scsi|virtio)\d+',
336 description
=> "The number of CPUs. Please use option -sockets instead.",
343 description
=> "The number of CPU sockets.",
350 description
=> "The number of cores per socket.",
357 description
=> "Enable/disable NUMA.",
363 description
=> "Enable/disable hugepages memory.",
364 enum
=> [qw(any 2 1024)],
369 description
=> "Number of hotplugged vcpus.",
376 description
=> "Enable/disable ACPI.",
382 description
=> "Enable/disable Qemu GuestAgent.",
388 description
=> "Enable/disable KVM hardware virtualization.",
394 description
=> "Enable/disable time drift fix.",
400 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
405 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
410 description
=> "Select the VGA type.",
411 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
412 " modes (>= 1280x1024x16) then you should use the options " .
413 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
414 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
415 "display sever. For win* OS you can select how many independent " .
416 "displays you want, Linux guests can add displays them self. " .
417 "You can also run without any graphic card, using a serial device" .
419 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
423 type
=> 'string', format
=> 'pve-qm-watchdog',
424 description
=> "Create a virtual hardware watchdog device.",
425 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
426 " (by a guest action), the watchdog must be periodically polled " .
427 "by an agent inside the guest or else the watchdog will reset " .
428 "the guest (or execute the respective action specified)",
433 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
434 description
=> "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
435 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
438 startup
=> get_standard_option
('pve-startup-order'),
442 description
=> "Enable/disable Template.",
448 description
=> "Arbitrary arguments passed to kvm.",
449 verbose_description
=> <<EODESCR,
450 Arbitrary arguments passed to kvm, for example:
452 args: -no-reboot -no-hpet
454 NOTE: this option is for experts only.
461 description
=> "Enable/disable the USB tablet device.",
462 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
463 "usually needed to allow absolute mouse positioning with VNC. " .
464 "Else the mouse runs out of sync with normal VNC clients. " .
465 "If you're running lots of console-only guests on one host, " .
466 "you may consider disabling this to save some context switches. " .
467 "This is turned off by default if you use spice (-vga=qxl).",
472 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
476 migrate_downtime
=> {
479 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
485 type
=> 'string', format
=> 'pve-qm-ide',
486 typetext
=> '<volume>',
487 description
=> "This is an alias for option -ide2",
491 description
=> "Emulated CPU type.",
495 parent
=> get_standard_option
('pve-snapshot-name', {
497 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
501 description
=> "Timestamp for snapshots.",
507 type
=> 'string', format
=> 'pve-volume-id',
508 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
510 vmstatestorage
=> get_standard_option
('pve-storage-id', {
511 description
=> "Default storage for VM state volumes/files.",
515 description
=> "Specific the Qemu machine type.",
517 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
522 description
=> "Specify SMBIOS type 1 fields.",
523 type
=> 'string', format
=> 'pve-qm-smbios1',
530 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
536 enum
=> [ qw(seabios ovmf) ],
537 description
=> "Select BIOS implementation.",
538 default => 'seabios',
542 my $confdesc_cloudinit = {
546 description
=> 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
547 enum
=> ['configdrive2', 'nocloud'],
552 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
557 description
=> 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
562 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.",
566 type
=> 'string', format
=> 'address-list',
567 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.",
572 format
=> 'urlencoded',
573 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
577 # what about other qemu settings ?
579 #machine => 'string',
592 ##soundhw => 'string',
594 while (my ($k, $v) = each %$confdesc) {
595 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
598 my $MAX_IDE_DISKS = 4;
599 my $MAX_SCSI_DISKS = 14;
600 my $MAX_VIRTIO_DISKS = 16;
601 my $MAX_SATA_DISKS = 6;
602 my $MAX_USB_DEVICES = 5;
604 my $MAX_UNUSED_DISKS = 8;
605 my $MAX_HOSTPCI_DEVICES = 4;
606 my $MAX_SERIAL_PORTS = 4;
607 my $MAX_PARALLEL_PORTS = 3;
613 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
614 description
=> "CPUs accessing this NUMA node.",
615 format_description
=> "id[-id];...",
619 description
=> "Amount of memory this NUMA node provides.",
624 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
625 description
=> "Host NUMA nodes to use.",
626 format_description
=> "id[-id];...",
631 enum
=> [qw(preferred bind interleave)],
632 description
=> "NUMA allocation policy.",
636 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
639 type
=> 'string', format
=> $numa_fmt,
640 description
=> "NUMA topology.",
642 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
644 for (my $i = 0; $i < $MAX_NUMA; $i++) {
645 $confdesc->{"numa$i"} = $numadesc;
648 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
649 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
650 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
651 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
653 my $net_fmt_bridge_descr = <<__EOD__;
654 Bridge to attach the network device to. The Proxmox VE standard bridge
657 If you do not specify a bridge, we create a kvm user (NATed) network
658 device, which provides DHCP and DNS services. The following addresses
665 The DHCP server assign addresses to the guest starting from 10.0.2.15.
671 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
672 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
673 format_description
=> "XX:XX:XX:XX:XX:XX",
678 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'.",
679 enum
=> $nic_model_list,
682 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
685 description
=> $net_fmt_bridge_descr,
686 format_description
=> 'bridge',
691 minimum
=> 0, maximum
=> 16,
692 description
=> 'Number of packet queues to be used on the device.',
698 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
703 minimum
=> 1, maximum
=> 4094,
704 description
=> 'VLAN tag to apply to packets on this interface.',
709 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
710 description
=> 'VLAN trunks to pass through this interface.',
711 format_description
=> 'vlanid[;vlanid...]',
716 description
=> 'Whether this interface should be protected by the firewall.',
721 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
728 type
=> 'string', format
=> $net_fmt,
729 description
=> "Specify network devices.",
732 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
737 format
=> 'pve-ipv4-config',
738 format_description
=> 'IPv4Format/CIDR',
739 description
=> 'IPv4 address in CIDR format.',
746 format_description
=> 'GatewayIPv4',
747 description
=> 'Default gateway for IPv4 traffic.',
753 format
=> 'pve-ipv6-config',
754 format_description
=> 'IPv6Format/CIDR',
755 description
=> 'IPv6 address in CIDR format.',
762 format_description
=> 'GatewayIPv6',
763 description
=> 'Default gateway for IPv6 traffic.',
768 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
771 type
=> 'string', format
=> 'pve-qm-ipconfig',
772 description
=> <<'EODESCR',
773 cloud-init: Specify IP addresses and gateways for the corresponding interface.
775 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
777 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
778 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
780 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
783 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
785 for (my $i = 0; $i < $MAX_NETS; $i++) {
786 $confdesc->{"net$i"} = $netdesc;
787 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
790 foreach my $key (keys %$confdesc_cloudinit) {
791 $confdesc->{$key} = $confdesc_cloudinit->{$key};
794 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
795 sub verify_volume_id_or_qm_path
{
796 my ($volid, $noerr) = @_;
798 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
802 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
803 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
805 return undef if $noerr;
813 my %drivedesc_base = (
814 volume
=> { alias
=> 'file' },
817 format
=> 'pve-volume-id-or-qm-path',
819 format_description
=> 'volume',
820 description
=> "The drive's backing volume.",
824 enum
=> [qw(cdrom disk)],
825 description
=> "The drive's media type.",
831 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
836 description
=> "Force the drive's physical geometry to have a specific head count.",
841 description
=> "Force the drive's physical geometry to have a specific sector count.",
846 enum
=> [qw(none lba auto)],
847 description
=> "Force disk geometry bios translation mode.",
852 description
=> "Controls qemu's snapshot mode feature."
853 . " If activated, changes made to the disk are temporary and will"
854 . " be discarded when the VM is shutdown.",
859 enum
=> [qw(none writethrough writeback unsafe directsync)],
860 description
=> "The drive's cache mode",
863 format
=> get_standard_option
('pve-qm-image-format'),
866 format
=> 'disk-size',
867 format_description
=> 'DiskSize',
868 description
=> "Disk size. This is purely informational and has no effect.",
873 description
=> "Whether the drive should be included when making backups.",
878 description
=> 'Whether the drive should considered for replication jobs.',
884 enum
=> [qw(ignore report stop)],
885 description
=> 'Read error action.',
890 enum
=> [qw(enospc ignore report stop)],
891 description
=> 'Write error action.',
896 enum
=> [qw(native threads)],
897 description
=> 'AIO type to use.',
902 enum
=> [qw(ignore on)],
903 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
908 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
913 format
=> 'urlencoded',
914 format_description
=> 'serial',
915 maxLength
=> 20*3, # *3 since it's %xx url enoded
916 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
921 description
=> 'Mark this locally-managed volume as available on all nodes',
922 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!",
928 my %iothread_fmt = ( iothread
=> {
930 description
=> "Whether to use iothreads for this drive",
937 format
=> 'urlencoded',
938 format_description
=> 'model',
939 maxLength
=> 40*3, # *3 since it's %xx url enoded
940 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
948 description
=> "Number of queues.",
954 my %scsiblock_fmt = (
957 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",
963 my $add_throttle_desc = sub {
964 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
967 format_description
=> $unit,
968 description
=> "Maximum $what in $longunit.",
971 $d->{minimum
} = $minimum if defined($minimum);
972 $drivedesc_base{$key} = $d;
974 # throughput: (leaky bucket)
975 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
976 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
977 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
978 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
979 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
980 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
981 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
982 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
983 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
985 # pools: (pool of IO before throttling starts taking effect)
986 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
987 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
988 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
989 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
990 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
991 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
994 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
995 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
996 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
997 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
998 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
999 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1002 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1003 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1004 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1005 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1011 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1015 type
=> 'string', format
=> $ide_fmt,
1016 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1018 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1028 type
=> 'string', format
=> $scsi_fmt,
1029 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1031 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1038 type
=> 'string', format
=> $sata_fmt,
1039 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1041 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1049 type
=> 'string', format
=> $virtio_fmt,
1050 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1052 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1054 my $alldrive_fmt = {
1063 volume
=> { alias
=> 'file' },
1066 format
=> 'pve-volume-id-or-qm-path',
1068 format_description
=> 'volume',
1069 description
=> "The drive's backing volume.",
1071 format
=> get_standard_option
('pve-qm-image-format'),
1074 format
=> 'disk-size',
1075 format_description
=> 'DiskSize',
1076 description
=> "Disk size. This is purely informational and has no effect.",
1081 my $efidisk_desc = {
1083 type
=> 'string', format
=> $efidisk_fmt,
1084 description
=> "Configure a Disk for storing EFI vars",
1087 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1092 type
=> 'string', format
=> 'pve-qm-usb-device',
1093 format_description
=> 'HOSTUSBDEVICE|spice',
1094 description
=> <<EODESCR,
1095 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1097 'bus-port(.port)*' (decimal numbers) or
1098 'vendor_id:product_id' (hexadeciaml numbers) or
1101 You can use the 'lsusb -t' command to list existing usb devices.
1103 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1105 The value 'spice' can be used to add a usb redirection devices for spice.
1111 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).",
1118 type
=> 'string', format
=> $usb_fmt,
1119 description
=> "Configure an USB device (n is 0 to 4).",
1121 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1123 # NOTE: the match-groups of this regex are used in parse_hostpci
1124 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1129 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1130 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1131 description
=> <<EODESCR,
1132 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1133 of PCI virtual functions of the host. HOSTPCIID syntax is:
1135 'bus:dev.func' (hexadecimal numbers)
1137 You can us the 'lspci' command to list existing PCI devices.
1142 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1148 pattern
=> '[^,;]+',
1149 format_description
=> 'string',
1150 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1155 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1161 description
=> "Enable vfio-vga device support.",
1166 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1170 type
=> 'string', format
=> 'pve-qm-hostpci',
1171 description
=> "Map host PCI devices into guest.",
1172 verbose_description
=> <<EODESCR,
1173 Map host PCI devices into guest.
1175 NOTE: This option allows direct access to host hardware. So it is no longer
1176 possible to migrate such machines - use with special care.
1178 CAUTION: Experimental! User reported problems with this option.
1181 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1186 pattern
=> '(/dev/.+|socket)',
1187 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1188 verbose_description
=> <<EODESCR,
1189 Create a serial device inside the VM (n is 0 to 3), and pass through a
1190 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1191 host side (use 'qm terminal' to open a terminal connection).
1193 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1195 CAUTION: Experimental! User reported problems with this option.
1202 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1203 description
=> "Map host parallel devices (n is 0 to 2).",
1204 verbose_description
=> <<EODESCR,
1205 Map host parallel devices (n is 0 to 2).
1207 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1209 CAUTION: Experimental! User reported problems with this option.
1213 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1214 $confdesc->{"parallel$i"} = $paralleldesc;
1217 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1218 $confdesc->{"serial$i"} = $serialdesc;
1221 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1222 $confdesc->{"hostpci$i"} = $hostpcidesc;
1225 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1226 $drivename_hash->{"ide$i"} = 1;
1227 $confdesc->{"ide$i"} = $idedesc;
1230 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1231 $drivename_hash->{"sata$i"} = 1;
1232 $confdesc->{"sata$i"} = $satadesc;
1235 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1236 $drivename_hash->{"scsi$i"} = 1;
1237 $confdesc->{"scsi$i"} = $scsidesc ;
1240 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1241 $drivename_hash->{"virtio$i"} = 1;
1242 $confdesc->{"virtio$i"} = $virtiodesc;
1245 $drivename_hash->{efidisk0
} = 1;
1246 $confdesc->{efidisk0
} = $efidisk_desc;
1248 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1249 $confdesc->{"usb$i"} = $usbdesc;
1254 type
=> 'string', format
=> 'pve-volume-id',
1255 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1258 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1259 $confdesc->{"unused$i"} = $unuseddesc;
1262 my $kvm_api_version = 0;
1266 return $kvm_api_version if $kvm_api_version;
1268 my $fh = IO
::File-
>new("</dev/kvm") ||
1271 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1272 $kvm_api_version = $v;
1277 return $kvm_api_version;
1280 my $kvm_user_version;
1282 sub kvm_user_version
{
1284 return $kvm_user_version if $kvm_user_version;
1286 $kvm_user_version = 'unknown';
1290 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1291 $kvm_user_version = $2;
1295 eval { run_command
("kvm -version", outfunc
=> $code); };
1298 return $kvm_user_version;
1302 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1304 sub valid_drive_names
{
1305 # order is important - used to autoselect boot disk
1306 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1307 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1308 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1309 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1313 sub is_valid_drivename
{
1316 return defined($drivename_hash->{$dev});
1321 return defined($confdesc->{$key});
1325 return $nic_model_list;
1328 sub os_list_description
{
1332 wxp
=> 'Windows XP',
1333 w2k
=> 'Windows 2000',
1334 w2k3
=>, 'Windows 2003',
1335 w2k8
=> 'Windows 2008',
1336 wvista
=> 'Windows Vista',
1337 win7
=> 'Windows 7',
1338 win8
=> 'Windows 8/2012',
1339 win10
=> 'Windows 10/2016',
1347 sub get_cdrom_path
{
1349 return $cdrom_path if $cdrom_path;
1351 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1352 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1353 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1357 my ($storecfg, $vmid, $cdrom) = @_;
1359 if ($cdrom eq 'cdrom') {
1360 return get_cdrom_path
();
1361 } elsif ($cdrom eq 'none') {
1363 } elsif ($cdrom =~ m
|^/|) {
1366 return PVE
::Storage
::path
($storecfg, $cdrom);
1370 # try to convert old style file names to volume IDs
1371 sub filename_to_volume_id
{
1372 my ($vmid, $file, $media) = @_;
1374 if (!($file eq 'none' || $file eq 'cdrom' ||
1375 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1377 return undef if $file =~ m
|/|;
1379 if ($media && $media eq 'cdrom') {
1380 $file = "local:iso/$file";
1382 $file = "local:$vmid/$file";
1389 sub verify_media_type
{
1390 my ($opt, $vtype, $media) = @_;
1395 if ($media eq 'disk') {
1397 } elsif ($media eq 'cdrom') {
1400 die "internal error";
1403 return if ($vtype eq $etype);
1405 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1408 sub cleanup_drive_path
{
1409 my ($opt, $storecfg, $drive) = @_;
1411 # try to convert filesystem paths to volume IDs
1413 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1414 ($drive->{file
} !~ m
|^/dev/.+|) &&
1415 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1416 ($drive->{file
} !~ m/^\d+$/)) {
1417 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1418 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1419 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1420 verify_media_type
($opt, $vtype, $drive->{media
});
1421 $drive->{file
} = $volid;
1424 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1427 sub parse_hotplug_features
{
1432 return $res if $data eq '0';
1434 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1436 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1437 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1440 die "invalid hotplug feature '$feature'\n";
1446 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1447 sub pve_verify_hotplug_features
{
1448 my ($value, $noerr) = @_;
1450 return $value if parse_hotplug_features
($value);
1452 return undef if $noerr;
1454 die "unable to parse hotplug option\n";
1457 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1458 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1459 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1460 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1461 # [,iothread=on][,serial=serial][,model=model]
1464 my ($key, $data) = @_;
1466 my ($interface, $index);
1468 if ($key =~ m/^([^\d]+)(\d+)$/) {
1475 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1476 : $confdesc->{$key}->{format
};
1478 warn "invalid drive key: $key\n";
1481 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1482 return undef if !$res;
1483 $res->{interface
} = $interface;
1484 $res->{index} = $index;
1487 foreach my $opt (qw(bps bps_rd bps_wr)) {
1488 if (my $bps = defined(delete $res->{$opt})) {
1489 if (defined($res->{"m$opt"})) {
1490 warn "both $opt and m$opt specified\n";
1494 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1498 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1499 for my $requirement (
1500 [mbps_max
=> 'mbps'],
1501 [mbps_rd_max
=> 'mbps_rd'],
1502 [mbps_wr_max
=> 'mbps_wr'],
1503 [miops_max
=> 'miops'],
1504 [miops_rd_max
=> 'miops_rd'],
1505 [miops_wr_max
=> 'miops_wr'],
1506 [bps_max_length
=> 'mbps_max'],
1507 [bps_rd_max_length
=> 'mbps_rd_max'],
1508 [bps_wr_max_length
=> 'mbps_wr_max'],
1509 [iops_max_length
=> 'iops_max'],
1510 [iops_rd_max_length
=> 'iops_rd_max'],
1511 [iops_wr_max_length
=> 'iops_wr_max']) {
1512 my ($option, $requires) = @$requirement;
1513 if ($res->{$option} && !$res->{$requires}) {
1514 warn "$option requires $requires\n";
1519 return undef if $error;
1521 return undef if $res->{mbps_rd
} && $res->{mbps
};
1522 return undef if $res->{mbps_wr
} && $res->{mbps
};
1523 return undef if $res->{iops_rd
} && $res->{iops
};
1524 return undef if $res->{iops_wr
} && $res->{iops
};
1526 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1527 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1528 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1529 return undef if $res->{interface
} eq 'virtio';
1532 if (my $size = $res->{size
}) {
1533 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1540 my ($vmid, $drive) = @_;
1541 my $data = { %$drive };
1542 delete $data->{$_} for qw(index interface);
1543 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1547 my($fh, $noerr) = @_;
1550 my $SG_GET_VERSION_NUM = 0x2282;
1552 my $versionbuf = "\x00" x
8;
1553 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1555 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1558 my $version = unpack("I", $versionbuf);
1559 if ($version < 30000) {
1560 die "scsi generic interface too old\n" if !$noerr;
1564 my $buf = "\x00" x
36;
1565 my $sensebuf = "\x00" x
8;
1566 my $cmd = pack("C x3 C x1", 0x12, 36);
1568 # see /usr/include/scsi/sg.h
1569 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";
1571 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1572 length($sensebuf), 0, length($buf), $buf,
1573 $cmd, $sensebuf, 6000);
1575 $ret = ioctl($fh, $SG_IO, $packet);
1577 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1581 my @res = unpack($sg_io_hdr_t, $packet);
1582 if ($res[17] || $res[18]) {
1583 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1588 (my $byte0, my $byte1, $res->{vendor
},
1589 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1591 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1592 $res->{type
} = $byte0 & 31;
1600 my $fh = IO
::File-
>new("+<$path") || return undef;
1601 my $res = scsi_inquiry
($fh, 1);
1607 sub machine_type_is_q35
{
1610 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1613 sub print_tabletdevice_full
{
1616 my $q35 = machine_type_is_q35
($conf);
1618 # we use uhci for old VMs because tablet driver was buggy in older qemu
1619 my $usbbus = $q35 ?
"ehci" : "uhci";
1621 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1624 sub print_drivedevice_full
{
1625 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1630 if ($drive->{interface
} eq 'virtio') {
1631 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1632 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1633 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1634 } elsif ($drive->{interface
} eq 'scsi') {
1636 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1637 my $unit = $drive->{index} % $maxdev;
1638 my $devicetype = 'hd';
1640 if (drive_is_cdrom
($drive)) {
1643 if ($drive->{file
} =~ m
|^/|) {
1644 $path = $drive->{file
};
1645 if (my $info = path_is_scsi
($path)) {
1646 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1647 $devicetype = 'block';
1648 } elsif ($info->{type
} == 1) { # tape
1649 $devicetype = 'generic';
1653 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1656 if($path =~ m/^iscsi\:\/\
//){
1657 $devicetype = 'generic';
1661 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1662 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1664 $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}";
1667 } elsif ($drive->{interface
} eq 'ide'){
1669 my $controller = int($drive->{index} / $maxdev);
1670 my $unit = $drive->{index} % $maxdev;
1671 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1673 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1674 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1675 $model = URI
::Escape
::uri_unescape
($model);
1676 $device .= ",model=$model";
1678 } elsif ($drive->{interface
} eq 'sata'){
1679 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1680 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1681 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1682 } elsif ($drive->{interface
} eq 'usb') {
1684 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1686 die "unsupported interface type";
1689 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1694 sub get_initiator_name
{
1697 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1698 while (defined(my $line = <$fh>)) {
1699 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1708 sub print_drive_full
{
1709 my ($storecfg, $vmid, $drive) = @_;
1712 my $volid = $drive->{file
};
1715 if (drive_is_cdrom
($drive)) {
1716 $path = get_iso_path
($storecfg, $vmid, $volid);
1718 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1720 $path = PVE
::Storage
::path
($storecfg, $volid);
1721 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1722 $format = qemu_img_format
($scfg, $volname);
1730 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1731 foreach my $o (@qemu_drive_options) {
1732 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1735 # snapshot only accepts on|off
1736 if (defined($drive->{snapshot
})) {
1737 my $v = $drive->{snapshot
} ?
'on' : 'off';
1738 $opts .= ",snapshot=$v";
1741 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1742 my ($dir, $qmpname) = @$type;
1743 if (my $v = $drive->{"mbps$dir"}) {
1744 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1746 if (my $v = $drive->{"mbps${dir}_max"}) {
1747 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1749 if (my $v = $drive->{"bps${dir}_max_length"}) {
1750 $opts .= ",throttling.bps$qmpname-max-length=$v";
1752 if (my $v = $drive->{"iops${dir}"}) {
1753 $opts .= ",throttling.iops$qmpname=$v";
1755 if (my $v = $drive->{"iops${dir}_max"}) {
1756 $opts .= ",throttling.iops$qmpname-max=$v";
1758 if (my $v = $drive->{"iops${dir}_max_length"}) {
1759 $opts .= ",throttling.iops$qmpname-max-length=$v";
1763 if (my $serial = $drive->{serial
}) {
1764 $serial = URI
::Escape
::uri_unescape
($serial);
1765 $opts .= ",serial=$serial";
1768 $opts .= ",format=$format" if $format && !$drive->{format
};
1770 my $cache_direct = 0;
1772 if (my $cache = $drive->{cache
}) {
1773 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1774 } elsif (!drive_is_cdrom
($drive)) {
1775 $opts .= ",cache=none";
1779 # aio native works only with O_DIRECT
1780 if (!$drive->{aio
}) {
1782 $opts .= ",aio=native";
1784 $opts .= ",aio=threads";
1788 if (!drive_is_cdrom
($drive)) {
1790 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1791 $detectzeroes = 'off';
1792 } elsif ($drive->{discard
}) {
1793 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1795 # This used to be our default with discard not being specified:
1796 $detectzeroes = 'on';
1798 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1801 my $pathinfo = $path ?
"file=$path," : '';
1803 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1806 sub print_netdevice_full
{
1807 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1809 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1811 my $device = $net->{model
};
1812 if ($net->{model
} eq 'virtio') {
1813 $device = 'virtio-net-pci';
1816 my $pciaddr = print_pci_addr
("$netid", $bridges);
1817 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1818 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1819 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1820 my $vectors = $net->{queues
} * 2 + 2;
1821 $tmpstr .= ",vectors=$vectors,mq=on";
1823 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1825 if ($use_old_bios_files) {
1827 if ($device eq 'virtio-net-pci') {
1828 $romfile = 'pxe-virtio.rom';
1829 } elsif ($device eq 'e1000') {
1830 $romfile = 'pxe-e1000.rom';
1831 } elsif ($device eq 'ne2k') {
1832 $romfile = 'pxe-ne2k_pci.rom';
1833 } elsif ($device eq 'pcnet') {
1834 $romfile = 'pxe-pcnet.rom';
1835 } elsif ($device eq 'rtl8139') {
1836 $romfile = 'pxe-rtl8139.rom';
1838 $tmpstr .= ",romfile=$romfile" if $romfile;
1844 sub print_netdev_full
{
1845 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1848 if ($netid =~ m/^net(\d+)$/) {
1852 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1854 my $ifname = "tap${vmid}i$i";
1856 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1857 die "interface name '$ifname' is too long (max 15 character)\n"
1858 if length($ifname) >= 16;
1860 my $vhostparam = '';
1861 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1863 my $vmname = $conf->{name
} || "vm$vmid";
1866 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1868 if ($net->{bridge
}) {
1869 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1871 $netdev = "type=user,id=$netid,hostname=$vmname";
1874 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1880 sub print_cpu_device
{
1881 my ($conf, $id) = @_;
1883 my $kvm = $conf->{kvm
} // 1;
1884 my $cpu = $kvm ?
"kvm64" : "qemu64";
1885 if (my $cputype = $conf->{cpu
}) {
1886 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1887 or die "Cannot parse cpu description: $cputype\n";
1888 $cpu = $cpuconf->{cputype
};
1891 my $cores = $conf->{cores
} || 1;
1893 my $current_core = ($id - 1) % $cores;
1894 my $current_socket = int(($id - 1 - $current_core)/$cores);
1896 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1899 sub drive_is_cloudinit
{
1901 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1904 sub drive_is_cdrom
{
1905 my ($drive, $exclude_cloudinit) = @_;
1907 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1909 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1913 sub parse_number_sets
{
1916 foreach my $part (split(/;/, $set)) {
1917 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1918 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1919 push @$res, [ $1, $2 ];
1921 die "invalid range: $part\n";
1930 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1931 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1932 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1939 return undef if !$value;
1941 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1943 my @idlist = split(/;/, $res->{host
});
1944 delete $res->{host
};
1945 foreach my $id (@idlist) {
1946 if ($id =~ /^$PCIRE$/) {
1948 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1950 my $pcidevices = lspci
($1);
1951 $res->{pciid
} = $pcidevices->{$1};
1954 # should have been caught by parse_property_string already
1955 die "failed to parse PCI id: $id\n";
1961 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1965 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1970 if (!defined($res->{macaddr
})) {
1971 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1972 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1977 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1978 sub parse_ipconfig
{
1981 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1987 if ($res->{gw
} && !$res->{ip
}) {
1988 warn 'gateway specified without specifying an IP address';
1991 if ($res->{gw6
} && !$res->{ip6
}) {
1992 warn 'IPv6 gateway specified without specifying an IPv6 address';
1995 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1996 warn 'gateway specified together with DHCP';
1999 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2001 warn "IPv6 gateway specified together with $res->{ip6} address";
2005 if (!$res->{ip
} && !$res->{ip6
}) {
2006 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2015 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2018 sub add_random_macs
{
2019 my ($settings) = @_;
2021 foreach my $opt (keys %$settings) {
2022 next if $opt !~ m/^net(\d+)$/;
2023 my $net = parse_net
($settings->{$opt});
2025 $settings->{$opt} = print_net
($net);
2029 sub vm_is_volid_owner
{
2030 my ($storecfg, $vmid, $volid) = @_;
2032 if ($volid !~ m
|^/|) {
2034 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2035 if ($owner && ($owner == $vmid)) {
2043 sub split_flagged_list
{
2044 my $text = shift || '';
2045 $text =~ s/[,;]/ /g;
2047 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2050 sub join_flagged_list
{
2051 my ($how, $lst) = @_;
2052 join $how, map { $lst->{$_} . $_ } keys %$lst;
2055 sub vmconfig_delete_pending_option
{
2056 my ($conf, $key, $force) = @_;
2058 delete $conf->{pending
}->{$key};
2059 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2060 $pending_delete_hash->{$key} = $force ?
'!' : '';
2061 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2064 sub vmconfig_undelete_pending_option
{
2065 my ($conf, $key) = @_;
2067 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2068 delete $pending_delete_hash->{$key};
2070 if (%$pending_delete_hash) {
2071 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2073 delete $conf->{pending
}->{delete};
2077 sub vmconfig_register_unused_drive
{
2078 my ($storecfg, $vmid, $conf, $drive) = @_;
2080 if (drive_is_cloudinit
($drive)) {
2081 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2083 } elsif (!drive_is_cdrom
($drive)) {
2084 my $volid = $drive->{file
};
2085 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2086 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2091 sub vmconfig_cleanup_pending
{
2094 # remove pending changes when nothing changed
2096 foreach my $opt (keys %{$conf->{pending
}}) {
2097 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2099 delete $conf->{pending
}->{$opt};
2103 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2104 my $pending_delete_hash = {};
2105 while (my ($opt, $force) = each %$current_delete_hash) {
2106 if (defined($conf->{$opt})) {
2107 $pending_delete_hash->{$opt} = $force;
2113 if (%$pending_delete_hash) {
2114 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2116 delete $conf->{pending
}->{delete};
2122 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2126 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2127 format_description
=> 'UUID',
2128 description
=> "Set SMBIOS1 UUID.",
2134 format_description
=> 'string',
2135 description
=> "Set SMBIOS1 version.",
2141 format_description
=> 'string',
2142 description
=> "Set SMBIOS1 serial number.",
2148 format_description
=> 'string',
2149 description
=> "Set SMBIOS1 manufacturer.",
2155 format_description
=> 'string',
2156 description
=> "Set SMBIOS1 product ID.",
2162 format_description
=> 'string',
2163 description
=> "Set SMBIOS1 SKU string.",
2169 format_description
=> 'string',
2170 description
=> "Set SMBIOS1 family string.",
2178 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2185 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2188 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2190 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2191 sub verify_bootdisk
{
2192 my ($value, $noerr) = @_;
2194 return $value if is_valid_drivename
($value);
2196 return undef if $noerr;
2198 die "invalid boot disk '$value'\n";
2201 sub parse_watchdog
{
2204 return undef if !$value;
2206 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2211 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2212 sub verify_usb_device
{
2213 my ($value, $noerr) = @_;
2215 return $value if parse_usb_device
($value);
2217 return undef if $noerr;
2219 die "unable to parse usb device\n";
2222 # add JSON properties for create and set function
2223 sub json_config_properties
{
2226 foreach my $opt (keys %$confdesc) {
2227 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2228 $prop->{$opt} = $confdesc->{$opt};
2234 # return copy of $confdesc_cloudinit to generate documentation
2235 sub cloudinit_config_properties
{
2237 return dclone
($confdesc_cloudinit);
2241 my ($key, $value) = @_;
2243 die "unknown setting '$key'\n" if !$confdesc->{$key};
2245 my $type = $confdesc->{$key}->{type
};
2247 if (!defined($value)) {
2248 die "got undefined value\n";
2251 if ($value =~ m/[\n\r]/) {
2252 die "property contains a line feed\n";
2255 if ($type eq 'boolean') {
2256 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2257 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2258 die "type check ('boolean') failed - got '$value'\n";
2259 } elsif ($type eq 'integer') {
2260 return int($1) if $value =~ m/^(\d+)$/;
2261 die "type check ('integer') failed - got '$value'\n";
2262 } elsif ($type eq 'number') {
2263 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2264 die "type check ('number') failed - got '$value'\n";
2265 } elsif ($type eq 'string') {
2266 if (my $fmt = $confdesc->{$key}->{format
}) {
2267 PVE
::JSONSchema
::check_format
($fmt, $value);
2270 $value =~ s/^\"(.*)\"$/$1/;
2273 die "internal error"
2277 sub check_iommu_support
{
2278 #fixme : need to check IOMMU support
2279 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2289 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2290 utime undef, undef, $conf;
2294 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2296 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2298 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2300 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2302 if ($conf->{template
}) {
2303 # check if any base image is still used by a linked clone
2304 foreach_drive
($conf, sub {
2305 my ($ds, $drive) = @_;
2307 return if drive_is_cdrom
($drive);
2309 my $volid = $drive->{file
};
2311 return if !$volid || $volid =~ m
|^/|;
2313 die "base volume '$volid' is still in use by linked cloned\n"
2314 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2319 # only remove disks owned by this VM
2320 foreach_drive
($conf, sub {
2321 my ($ds, $drive) = @_;
2323 return if drive_is_cdrom
($drive, 1);
2325 my $volid = $drive->{file
};
2327 return if !$volid || $volid =~ m
|^/|;
2329 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2330 return if !$path || !$owner || ($owner != $vmid);
2333 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2335 warn "Could not remove disk '$volid', check manually: $@" if $@;
2339 if ($keep_empty_config) {
2340 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2345 # also remove unused disk
2347 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2350 PVE
::Storage
::foreach_volid
($dl, sub {
2351 my ($volid, $sid, $volname, $d) = @_;
2352 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2361 sub parse_vm_config
{
2362 my ($filename, $raw) = @_;
2364 return undef if !defined($raw);
2367 digest
=> Digest
::SHA
::sha1_hex
($raw),
2372 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2373 || die "got strange filename '$filename'";
2381 my @lines = split(/\n/, $raw);
2382 foreach my $line (@lines) {
2383 next if $line =~ m/^\s*$/;
2385 if ($line =~ m/^\[PENDING\]\s*$/i) {
2386 $section = 'pending';
2387 if (defined($descr)) {
2389 $conf->{description
} = $descr;
2392 $conf = $res->{$section} = {};
2395 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2397 if (defined($descr)) {
2399 $conf->{description
} = $descr;
2402 $conf = $res->{snapshots
}->{$section} = {};
2406 if ($line =~ m/^\#(.*)\s*$/) {
2407 $descr = '' if !defined($descr);
2408 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2412 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2413 $descr = '' if !defined($descr);
2414 $descr .= PVE
::Tools
::decode_text
($2);
2415 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2416 $conf->{snapstate
} = $1;
2417 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2420 $conf->{$key} = $value;
2421 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2423 if ($section eq 'pending') {
2424 $conf->{delete} = $value; # we parse this later
2426 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2428 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2431 eval { $value = check_type
($key, $value); };
2433 warn "vm $vmid - unable to parse value of '$key' - $@";
2435 $key = 'ide2' if $key eq 'cdrom';
2436 my $fmt = $confdesc->{$key}->{format
};
2437 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2438 my $v = parse_drive
($key, $value);
2439 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2440 $v->{file
} = $volid;
2441 $value = print_drive
($vmid, $v);
2443 warn "vm $vmid - unable to parse value of '$key'\n";
2448 $conf->{$key} = $value;
2453 if (defined($descr)) {
2455 $conf->{description
} = $descr;
2457 delete $res->{snapstate
}; # just to be sure
2462 sub write_vm_config
{
2463 my ($filename, $conf) = @_;
2465 delete $conf->{snapstate
}; # just to be sure
2467 if ($conf->{cdrom
}) {
2468 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2469 $conf->{ide2
} = $conf->{cdrom
};
2470 delete $conf->{cdrom
};
2473 # we do not use 'smp' any longer
2474 if ($conf->{sockets
}) {
2475 delete $conf->{smp
};
2476 } elsif ($conf->{smp
}) {
2477 $conf->{sockets
} = $conf->{smp
};
2478 delete $conf->{cores
};
2479 delete $conf->{smp
};
2482 my $used_volids = {};
2484 my $cleanup_config = sub {
2485 my ($cref, $pending, $snapname) = @_;
2487 foreach my $key (keys %$cref) {
2488 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2489 $key eq 'snapstate' || $key eq 'pending';
2490 my $value = $cref->{$key};
2491 if ($key eq 'delete') {
2492 die "propertry 'delete' is only allowed in [PENDING]\n"
2494 # fixme: check syntax?
2497 eval { $value = check_type
($key, $value); };
2498 die "unable to parse value of '$key' - $@" if $@;
2500 $cref->{$key} = $value;
2502 if (!$snapname && is_valid_drivename
($key)) {
2503 my $drive = parse_drive
($key, $value);
2504 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2509 &$cleanup_config($conf);
2511 &$cleanup_config($conf->{pending
}, 1);
2513 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2514 die "internal error" if $snapname eq 'pending';
2515 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2518 # remove 'unusedX' settings if we re-add a volume
2519 foreach my $key (keys %$conf) {
2520 my $value = $conf->{$key};
2521 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2522 delete $conf->{$key};
2526 my $generate_raw_config = sub {
2527 my ($conf, $pending) = @_;
2531 # add description as comment to top of file
2532 if (defined(my $descr = $conf->{description
})) {
2534 foreach my $cl (split(/\n/, $descr)) {
2535 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2538 $raw .= "#\n" if $pending;
2542 foreach my $key (sort keys %$conf) {
2543 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2544 $raw .= "$key: $conf->{$key}\n";
2549 my $raw = &$generate_raw_config($conf);
2551 if (scalar(keys %{$conf->{pending
}})){
2552 $raw .= "\n[PENDING]\n";
2553 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2556 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2557 $raw .= "\n[$snapname]\n";
2558 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2568 # we use static defaults from our JSON schema configuration
2569 foreach my $key (keys %$confdesc) {
2570 if (defined(my $default = $confdesc->{$key}->{default})) {
2571 $res->{$key} = $default;
2575 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2576 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2582 my $vmlist = PVE
::Cluster
::get_vmlist
();
2584 return $res if !$vmlist || !$vmlist->{ids
};
2585 my $ids = $vmlist->{ids
};
2587 foreach my $vmid (keys %$ids) {
2588 my $d = $ids->{$vmid};
2589 next if !$d->{node
} || $d->{node
} ne $nodename;
2590 next if !$d->{type
} || $d->{type
} ne 'qemu';
2591 $res->{$vmid}->{exists} = 1;
2596 # test if VM uses local resources (to prevent migration)
2597 sub check_local_resources
{
2598 my ($conf, $noerr) = @_;
2602 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2603 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2605 foreach my $k (keys %$conf) {
2606 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2607 # sockets are safe: they will recreated be on the target side post-migrate
2608 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2609 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2612 die "VM uses local resources\n" if $loc_res && !$noerr;
2617 # check if used storages are available on all nodes (use by migrate)
2618 sub check_storage_availability
{
2619 my ($storecfg, $conf, $node) = @_;
2621 foreach_drive
($conf, sub {
2622 my ($ds, $drive) = @_;
2624 my $volid = $drive->{file
};
2627 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2630 # check if storage is available on both nodes
2631 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2632 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2636 # list nodes where all VM images are available (used by has_feature API)
2638 my ($conf, $storecfg) = @_;
2640 my $nodelist = PVE
::Cluster
::get_nodelist
();
2641 my $nodehash = { map { $_ => 1 } @$nodelist };
2642 my $nodename = PVE
::INotify
::nodename
();
2644 foreach_drive
($conf, sub {
2645 my ($ds, $drive) = @_;
2647 my $volid = $drive->{file
};
2650 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2652 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2653 if ($scfg->{disable
}) {
2655 } elsif (my $avail = $scfg->{nodes
}) {
2656 foreach my $node (keys %$nodehash) {
2657 delete $nodehash->{$node} if !$avail->{$node};
2659 } elsif (!$scfg->{shared
}) {
2660 foreach my $node (keys %$nodehash) {
2661 delete $nodehash->{$node} if $node ne $nodename
2671 my ($pidfile, $pid) = @_;
2673 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2677 return undef if !$line;
2678 my @param = split(/\0/, $line);
2680 my $cmd = $param[0];
2681 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2683 for (my $i = 0; $i < scalar (@param); $i++) {
2686 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2687 my $p = $param[$i+1];
2688 return 1 if $p && ($p eq $pidfile);
2697 my ($vmid, $nocheck, $node) = @_;
2699 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2701 die "unable to find configuration file for VM $vmid - no such machine\n"
2702 if !$nocheck && ! -f
$filename;
2704 my $pidfile = pidfile_name
($vmid);
2706 if (my $fd = IO
::File-
>new("<$pidfile")) {
2711 my $mtime = $st->mtime;
2712 if ($mtime > time()) {
2713 warn "file '$filename' modified in future\n";
2716 if ($line =~ m/^(\d+)$/) {
2718 if (check_cmdline
($pidfile, $pid)) {
2719 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2731 my $vzlist = config_list
();
2733 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2735 while (defined(my $de = $fd->read)) {
2736 next if $de !~ m/^(\d+)\.pid$/;
2738 next if !defined($vzlist->{$vmid});
2739 if (my $pid = check_running
($vmid)) {
2740 $vzlist->{$vmid}->{pid
} = $pid;
2748 my ($storecfg, $conf) = @_;
2750 my $bootdisk = $conf->{bootdisk
};
2751 return undef if !$bootdisk;
2752 return undef if !is_valid_drivename
($bootdisk);
2754 return undef if !$conf->{$bootdisk};
2756 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2757 return undef if !defined($drive);
2759 return undef if drive_is_cdrom
($drive);
2761 my $volid = $drive->{file
};
2762 return undef if !$volid;
2764 return $drive->{size
};
2767 my $last_proc_pid_stat;
2769 # get VM status information
2770 # This must be fast and should not block ($full == false)
2771 # We only query KVM using QMP if $full == true (this can be slow)
2773 my ($opt_vmid, $full) = @_;
2777 my $storecfg = PVE
::Storage
::config
();
2779 my $list = vzlist
();
2780 my $defaults = load_defaults
();
2782 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2784 my $cpucount = $cpuinfo->{cpus
} || 1;
2786 foreach my $vmid (keys %$list) {
2787 next if $opt_vmid && ($vmid ne $opt_vmid);
2789 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2790 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2793 $d->{pid
} = $list->{$vmid}->{pid
};
2795 # fixme: better status?
2796 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2798 my $size = disksize
($storecfg, $conf);
2799 if (defined($size)) {
2800 $d->{disk
} = 0; # no info available
2801 $d->{maxdisk
} = $size;
2807 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2808 * ($conf->{cores
} || $defaults->{cores
});
2809 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2810 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2812 $d->{name
} = $conf->{name
} || "VM $vmid";
2813 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2814 : $defaults->{memory
}*(1024*1024);
2816 if ($conf->{balloon
}) {
2817 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2818 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2819 : $defaults->{shares
};
2830 $d->{diskwrite
} = 0;
2832 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2834 $d->{serial
} = 1 if conf_has_serial
($conf);
2839 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2840 foreach my $dev (keys %$netdev) {
2841 next if $dev !~ m/^tap([1-9]\d*)i/;
2843 my $d = $res->{$vmid};
2846 $d->{netout
} += $netdev->{$dev}->{receive
};
2847 $d->{netin
} += $netdev->{$dev}->{transmit
};
2850 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2851 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2856 my $ctime = gettimeofday
;
2858 foreach my $vmid (keys %$list) {
2860 my $d = $res->{$vmid};
2861 my $pid = $d->{pid
};
2864 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2865 next if !$pstat; # not running
2867 my $used = $pstat->{utime} + $pstat->{stime
};
2869 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2871 if ($pstat->{vsize
}) {
2872 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2875 my $old = $last_proc_pid_stat->{$pid};
2877 $last_proc_pid_stat->{$pid} = {
2885 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2887 if ($dtime > 1000) {
2888 my $dutime = $used - $old->{used
};
2890 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2891 $last_proc_pid_stat->{$pid} = {
2897 $d->{cpu
} = $old->{cpu
};
2901 return $res if !$full;
2903 my $qmpclient = PVE
::QMPClient-
>new();
2905 my $ballooncb = sub {
2906 my ($vmid, $resp) = @_;
2908 my $info = $resp->{'return'};
2909 return if !$info->{max_mem
};
2911 my $d = $res->{$vmid};
2913 # use memory assigned to VM
2914 $d->{maxmem
} = $info->{max_mem
};
2915 $d->{balloon
} = $info->{actual
};
2917 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2918 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2919 $d->{freemem
} = $info->{free_mem
};
2922 $d->{ballooninfo
} = $info;
2925 my $blockstatscb = sub {
2926 my ($vmid, $resp) = @_;
2927 my $data = $resp->{'return'} || [];
2928 my $totalrdbytes = 0;
2929 my $totalwrbytes = 0;
2931 for my $blockstat (@$data) {
2932 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2933 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2935 $blockstat->{device
} =~ s/drive-//;
2936 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2938 $res->{$vmid}->{diskread
} = $totalrdbytes;
2939 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2942 my $statuscb = sub {
2943 my ($vmid, $resp) = @_;
2945 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2946 # this fails if ballon driver is not loaded, so this must be
2947 # the last commnand (following command are aborted if this fails).
2948 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2950 my $status = 'unknown';
2951 if (!defined($status = $resp->{'return'}->{status
})) {
2952 warn "unable to get VM status\n";
2956 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2959 foreach my $vmid (keys %$list) {
2960 next if $opt_vmid && ($vmid ne $opt_vmid);
2961 next if !$res->{$vmid}->{pid
}; # not running
2962 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2965 $qmpclient->queue_execute(undef, 2);
2967 foreach my $vmid (keys %$list) {
2968 next if $opt_vmid && ($vmid ne $opt_vmid);
2969 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2976 my ($conf, $func, @param) = @_;
2978 foreach my $ds (valid_drive_names
()) {
2979 next if !defined($conf->{$ds});
2981 my $drive = parse_drive
($ds, $conf->{$ds});
2984 &$func($ds, $drive, @param);
2989 my ($conf, $func, @param) = @_;
2993 my $test_volid = sub {
2994 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
2998 $volhash->{$volid}->{cdrom
} //= 1;
2999 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3001 $volhash->{$volid}->{replicate
} //= 0;
3002 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3004 $volhash->{$volid}->{shared
} //= 0;
3005 $volhash->{$volid}->{shared
} = 1 if $shared;
3007 $volhash->{$volid}->{referenced_in_config
} //= 0;
3008 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3010 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3011 if defined($snapname);
3014 foreach_drive
($conf, sub {
3015 my ($ds, $drive) = @_;
3016 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3019 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3020 my $snap = $conf->{snapshots
}->{$snapname};
3021 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3022 foreach_drive
($snap, sub {
3023 my ($ds, $drive) = @_;
3024 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3028 foreach my $volid (keys %$volhash) {
3029 &$func($volid, $volhash->{$volid}, @param);
3033 sub conf_has_serial
{
3036 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3037 if ($conf->{"serial$i"}) {
3045 sub vga_conf_has_spice
{
3048 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3053 sub config_to_command
{
3054 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3057 my $globalFlags = [];
3058 my $machineFlags = [];
3064 my $kvmver = kvm_user_version
();
3065 my $vernum = 0; # unknown
3066 my $ostype = $conf->{ostype
};
3067 my $winversion = windows_version
($ostype);
3068 my $kvm = $conf->{kvm
} // 1;
3070 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3072 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3073 $vernum = $1*1000000+$2*1000;
3074 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3075 $vernum = $1*1000000+$2*1000+$3;
3078 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3080 my $have_ovz = -f
'/proc/vz/vestat';
3082 my $q35 = machine_type_is_q35
($conf);
3083 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3084 my $machine_type = $forcemachine || $conf->{machine
};
3085 my $use_old_bios_files = undef;
3086 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3088 my $cpuunits = defined($conf->{cpuunits
}) ?
3089 $conf->{cpuunits
} : $defaults->{cpuunits
};
3091 push @$cmd, '/usr/bin/kvm';
3093 push @$cmd, '-id', $vmid;
3095 my $vmname = $conf->{name
} || "vm$vmid";
3097 push @$cmd, '-name', $vmname;
3101 my $qmpsocket = qmp_socket
($vmid);
3102 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3103 push @$cmd, '-mon', "chardev=qmp,mode=control";
3106 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3108 push @$cmd, '-daemonize';
3110 if ($conf->{smbios1
}) {
3111 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3114 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3115 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3119 if (my $efidisk = $conf->{efidisk0
}) {
3120 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3121 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3122 $format = $d->{format
};
3124 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3125 if (!defined($format)) {
3126 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3127 $format = qemu_img_format
($scfg, $volname);
3131 die "efidisk format must be specified\n"
3132 if !defined($format);
3135 warn "no efidisk configured! Using temporary efivars disk.\n";
3136 $path = "/tmp/$vmid-ovmf.fd";
3137 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3141 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3142 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3146 # add usb controllers
3147 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3148 push @$devices, @usbcontrollers if @usbcontrollers;
3149 my $vga = $conf->{vga
};
3151 my $qxlnum = vga_conf_has_spice
($vga);
3152 $vga = 'qxl' if $qxlnum;
3155 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3156 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3158 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3162 # enable absolute mouse coordinates (needed by vnc)
3164 if (defined($conf->{tablet
})) {
3165 $tablet = $conf->{tablet
};
3167 $tablet = $defaults->{tablet
};
3168 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3169 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3172 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3175 my $gpu_passthrough;
3178 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3179 my $d = parse_hostpci
($conf->{"hostpci$i"});
3182 my $pcie = $d->{pcie
};
3184 die "q35 machine model is not enabled" if !$q35;
3185 $pciaddr = print_pcie_addr
("hostpci$i");
3187 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3190 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3191 my $romfile = $d->{romfile
};
3194 if ($d->{'x-vga'}) {
3195 $xvga = ',x-vga=on';
3198 $gpu_passthrough = 1;
3200 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3204 my $pcidevices = $d->{pciid
};
3205 my $multifunction = 1 if @$pcidevices > 1;
3208 foreach my $pcidevice (@$pcidevices) {
3210 my $id = "hostpci$i";
3211 $id .= ".$j" if $multifunction;
3212 my $addr = $pciaddr;
3213 $addr .= ".$j" if $multifunction;
3214 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3217 $devicestr .= "$rombar$xvga";
3218 $devicestr .= ",multifunction=on" if $multifunction;
3219 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3222 push @$devices, '-device', $devicestr;
3228 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3229 push @$devices, @usbdevices if @usbdevices;
3231 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3232 if (my $path = $conf->{"serial$i"}) {
3233 if ($path eq 'socket') {
3234 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3235 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3236 push @$devices, '-device', "isa-serial,chardev=serial$i";
3238 die "no such serial device\n" if ! -c
$path;
3239 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3240 push @$devices, '-device', "isa-serial,chardev=serial$i";
3246 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3247 if (my $path = $conf->{"parallel$i"}) {
3248 die "no such parallel device\n" if ! -c
$path;
3249 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3250 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3251 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3257 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3258 $sockets = $conf->{sockets
} if $conf->{sockets
};
3260 my $cores = $conf->{cores
} || 1;
3262 my $maxcpus = $sockets * $cores;
3264 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3266 my $allowed_vcpus = $cpuinfo->{cpus
};
3268 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3269 if ($allowed_vcpus < $maxcpus);
3271 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3273 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3274 for (my $i = 2; $i <= $vcpus; $i++) {
3275 my $cpustr = print_cpu_device
($conf,$i);
3276 push @$cmd, '-device', $cpustr;
3281 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3283 push @$cmd, '-nodefaults';
3285 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3287 my $bootindex_hash = {};
3289 foreach my $o (split(//, $bootorder)) {
3290 $bootindex_hash->{$o} = $i*100;
3294 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3296 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3298 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3300 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3302 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3303 my $socket = vnc_socket
($vmid);
3304 push @$cmd, '-vnc', "unix:$socket,x509,password";
3306 push @$cmd, '-nographic';
3310 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3312 my $useLocaltime = $conf->{localtime};
3314 if ($winversion >= 5) { # windows
3315 $useLocaltime = 1 if !defined($conf->{localtime});
3317 # use time drift fix when acpi is enabled
3318 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3319 $tdf = 1 if !defined($conf->{tdf
});
3323 if ($winversion >= 6) {
3324 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3325 push @$cmd, '-no-hpet';
3328 push @$rtcFlags, 'driftfix=slew' if $tdf;
3331 push @$machineFlags, 'accel=tcg';
3334 if ($machine_type) {
3335 push @$machineFlags, "type=${machine_type}";
3338 if ($conf->{startdate
}) {
3339 push @$rtcFlags, "base=$conf->{startdate}";
3340 } elsif ($useLocaltime) {
3341 push @$rtcFlags, 'base=localtime';
3344 my $cpu = $kvm ?
"kvm64" : "qemu64";
3345 if (my $cputype = $conf->{cpu
}) {
3346 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3347 or die "Cannot parse cpu description: $cputype\n";
3348 $cpu = $cpuconf->{cputype
};
3349 $kvm_off = 1 if $cpuconf->{hidden
};
3351 if (defined(my $flags = $cpuconf->{flags
})) {
3352 push @$cpuFlags, split(";", $flags);
3356 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3358 push @$cpuFlags , '-x2apic'
3359 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3361 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3363 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3365 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3367 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3368 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3371 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3373 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3375 push @$cpuFlags, 'kvm=off' if $kvm_off;
3377 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3378 die "internal error"; # should not happen
3380 push @$cpuFlags, "vendor=${cpu_vendor}"
3381 if $cpu_vendor ne 'default';
3383 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3385 push @$cmd, '-cpu', $cpu;
3387 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3389 push @$cmd, '-S' if $conf->{freeze
};
3391 # set keyboard layout
3392 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3393 push @$cmd, '-k', $kb if $kb;
3396 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3397 #push @$cmd, '-soundhw', 'es1370';
3398 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3400 if($conf->{agent
}) {
3401 my $qgasocket = qmp_socket
($vmid, 1);
3402 my $pciaddr = print_pci_addr
("qga0", $bridges);
3403 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3404 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3405 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3413 for(my $i = 1; $i < $qxlnum; $i++){
3414 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3415 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3418 # assume other OS works like Linux
3419 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3420 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3424 my $pciaddr = print_pci_addr
("spice", $bridges);
3426 my $nodename = PVE
::INotify
::nodename
();
3427 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3428 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3429 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3430 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3431 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3433 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3435 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3436 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3437 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3440 # enable balloon by default, unless explicitly disabled
3441 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3442 $pciaddr = print_pci_addr
("balloon0", $bridges);
3443 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3446 if ($conf->{watchdog
}) {
3447 my $wdopts = parse_watchdog
($conf->{watchdog
});
3448 $pciaddr = print_pci_addr
("watchdog", $bridges);
3449 my $watchdog = $wdopts->{model
} || 'i6300esb';
3450 push @$devices, '-device', "$watchdog$pciaddr";
3451 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3455 my $scsicontroller = {};
3456 my $ahcicontroller = {};
3457 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3459 # Add iscsi initiator name if available
3460 if (my $initiator = get_initiator_name
()) {
3461 push @$devices, '-iscsi', "initiator-name=$initiator";
3464 foreach_drive
($conf, sub {
3465 my ($ds, $drive) = @_;
3467 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3468 push @$vollist, $drive->{file
};
3471 # ignore efidisk here, already added in bios/fw handling code above
3472 return if $drive->{interface
} eq 'efidisk';
3474 $use_virtio = 1 if $ds =~ m/^virtio/;
3476 if (drive_is_cdrom
($drive)) {
3477 if ($bootindex_hash->{d
}) {
3478 $drive->{bootindex
} = $bootindex_hash->{d
};
3479 $bootindex_hash->{d
} += 1;
3482 if ($bootindex_hash->{c
}) {
3483 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3484 $bootindex_hash->{c
} += 1;
3488 if($drive->{interface
} eq 'virtio'){
3489 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3492 if ($drive->{interface
} eq 'scsi') {
3494 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3496 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3497 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3500 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3501 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3502 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3503 } elsif ($drive->{iothread
}) {
3504 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3508 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3509 $queues = ",num_queues=$drive->{queues}";
3512 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3513 $scsicontroller->{$controller}=1;
3516 if ($drive->{interface
} eq 'sata') {
3517 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3518 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3519 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3520 $ahcicontroller->{$controller}=1;
3523 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3524 push @$devices, '-drive',$drive_cmd;
3525 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3528 for (my $i = 0; $i < $MAX_NETS; $i++) {
3529 next if !$conf->{"net$i"};
3530 my $d = parse_net
($conf->{"net$i"});
3533 $use_virtio = 1 if $d->{model
} eq 'virtio';
3535 if ($bootindex_hash->{n
}) {
3536 $d->{bootindex
} = $bootindex_hash->{n
};
3537 $bootindex_hash->{n
} += 1;
3540 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3541 push @$devices, '-netdev', $netdevfull;
3543 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3544 push @$devices, '-device', $netdevicefull;
3549 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3554 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3556 while (my ($k, $v) = each %$bridges) {
3557 $pciaddr = print_pci_addr
("pci.$k");
3558 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3563 if ($conf->{args
}) {
3564 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3568 push @$cmd, @$devices;
3569 push @$cmd, '-rtc', join(',', @$rtcFlags)
3570 if scalar(@$rtcFlags);
3571 push @$cmd, '-machine', join(',', @$machineFlags)
3572 if scalar(@$machineFlags);
3573 push @$cmd, '-global', join(',', @$globalFlags)
3574 if scalar(@$globalFlags);
3576 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3581 return "${var_run_tmpdir}/$vmid.vnc";
3587 my $res = vm_mon_cmd
($vmid, 'query-spice');
3589 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3593 my ($vmid, $qga) = @_;
3594 my $sockettype = $qga ?
'qga' : 'qmp';
3595 return "${var_run_tmpdir}/$vmid.$sockettype";
3600 return "${var_run_tmpdir}/$vmid.pid";
3603 sub vm_devices_list
{
3606 my $res = vm_mon_cmd
($vmid, 'query-pci');
3608 foreach my $pcibus (@$res) {
3609 foreach my $device (@{$pcibus->{devices
}}) {
3610 next if !$device->{'qdev_id'};
3611 if ($device->{'pci_bridge'}) {
3612 $devices->{$device->{'qdev_id'}} = 1;
3613 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3614 next if !$bridge_device->{'qdev_id'};
3615 $devices->{$bridge_device->{'qdev_id'}} = 1;
3616 $devices->{$device->{'qdev_id'}}++;
3619 $devices->{$device->{'qdev_id'}} = 1;
3624 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3625 foreach my $block (@$resblock) {
3626 if($block->{device
} =~ m/^drive-(\S+)/){
3631 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3632 foreach my $mice (@$resmice) {
3633 if ($mice->{name
} eq 'QEMU HID Tablet') {
3634 $devices->{tablet
} = 1;
3639 # for usb devices there is no query-usb
3640 # but we can iterate over the entries in
3641 # qom-list path=/machine/peripheral
3642 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3643 foreach my $per (@$resperipheral) {
3644 if ($per->{name
} =~ m/^usb\d+$/) {
3645 $devices->{$per->{name
}} = 1;
3653 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3655 my $q35 = machine_type_is_q35
($conf);
3657 my $devices_list = vm_devices_list
($vmid);
3658 return 1 if defined($devices_list->{$deviceid});
3660 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3662 if ($deviceid eq 'tablet') {
3664 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3666 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3668 die "usb hotplug currently not reliable\n";
3669 # since we can't reliably hot unplug all added usb devices
3670 # and usb passthrough disables live migration
3671 # we disable usb hotplugging for now
3672 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3674 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3676 qemu_iothread_add
($vmid, $deviceid, $device);
3678 qemu_driveadd
($storecfg, $vmid, $device);
3679 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3681 qemu_deviceadd
($vmid, $devicefull);
3682 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3684 eval { qemu_drivedel
($vmid, $deviceid); };
3689 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3692 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3693 my $pciaddr = print_pci_addr
($deviceid);
3694 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3696 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3698 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3699 qemu_iothread_add
($vmid, $deviceid, $device);
3700 $devicefull .= ",iothread=iothread-$deviceid";
3703 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3704 $devicefull .= ",num_queues=$device->{queues}";
3707 qemu_deviceadd
($vmid, $devicefull);
3708 qemu_deviceaddverify
($vmid, $deviceid);
3710 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3712 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3713 qemu_driveadd
($storecfg, $vmid, $device);
3715 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3716 eval { qemu_deviceadd
($vmid, $devicefull); };
3718 eval { qemu_drivedel
($vmid, $deviceid); };
3723 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3725 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3727 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3728 my $use_old_bios_files = undef;
3729 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3731 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3732 qemu_deviceadd
($vmid, $netdevicefull);
3733 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3735 eval { qemu_netdevdel
($vmid, $deviceid); };
3740 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3743 my $pciaddr = print_pci_addr
($deviceid);
3744 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3746 qemu_deviceadd
($vmid, $devicefull);
3747 qemu_deviceaddverify
($vmid, $deviceid);
3750 die "can't hotplug device '$deviceid'\n";
3756 # fixme: this should raise exceptions on error!
3757 sub vm_deviceunplug
{
3758 my ($vmid, $conf, $deviceid) = @_;
3760 my $devices_list = vm_devices_list
($vmid);
3761 return 1 if !defined($devices_list->{$deviceid});
3763 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3765 if ($deviceid eq 'tablet') {
3767 qemu_devicedel
($vmid, $deviceid);
3769 } elsif ($deviceid =~ m/^usb\d+$/) {
3771 die "usb hotplug currently not reliable\n";
3772 # when unplugging usb devices this way,
3773 # there may be remaining usb controllers/hubs
3774 # so we disable it for now
3775 qemu_devicedel
($vmid, $deviceid);
3776 qemu_devicedelverify
($vmid, $deviceid);
3778 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3780 qemu_devicedel
($vmid, $deviceid);
3781 qemu_devicedelverify
($vmid, $deviceid);
3782 qemu_drivedel
($vmid, $deviceid);
3783 qemu_iothread_del
($conf, $vmid, $deviceid);
3785 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3787 qemu_devicedel
($vmid, $deviceid);
3788 qemu_devicedelverify
($vmid, $deviceid);
3789 qemu_iothread_del
($conf, $vmid, $deviceid);
3791 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3793 qemu_devicedel
($vmid, $deviceid);
3794 qemu_drivedel
($vmid, $deviceid);
3795 qemu_deletescsihw
($conf, $vmid, $deviceid);
3797 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3799 qemu_devicedel
($vmid, $deviceid);
3800 qemu_devicedelverify
($vmid, $deviceid);
3801 qemu_netdevdel
($vmid, $deviceid);
3804 die "can't unplug device '$deviceid'\n";
3810 sub qemu_deviceadd
{
3811 my ($vmid, $devicefull) = @_;
3813 $devicefull = "driver=".$devicefull;
3814 my %options = split(/[=,]/, $devicefull);
3816 vm_mon_cmd
($vmid, "device_add" , %options);
3819 sub qemu_devicedel
{
3820 my ($vmid, $deviceid) = @_;
3822 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3825 sub qemu_iothread_add
{
3826 my($vmid, $deviceid, $device) = @_;
3828 if ($device->{iothread
}) {
3829 my $iothreads = vm_iothreads_list
($vmid);
3830 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3834 sub qemu_iothread_del
{
3835 my($conf, $vmid, $deviceid) = @_;
3837 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3838 if ($device->{iothread
}) {
3839 my $iothreads = vm_iothreads_list
($vmid);
3840 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3844 sub qemu_objectadd
{
3845 my($vmid, $objectid, $qomtype) = @_;
3847 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3852 sub qemu_objectdel
{
3853 my($vmid, $objectid) = @_;
3855 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3861 my ($storecfg, $vmid, $device) = @_;
3863 my $drive = print_drive_full
($storecfg, $vmid, $device);
3864 $drive =~ s/\\/\\\\/g;
3865 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3867 # If the command succeeds qemu prints: "OK
"
3868 return 1 if $ret =~ m/OK/s;
3870 die "adding drive failed
: $ret\n";
3874 my($vmid, $deviceid) = @_;
3876 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3879 return 1 if $ret eq "";
3881 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3882 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3884 die "deleting drive
$deviceid failed
: $ret\n";
3887 sub qemu_deviceaddverify {
3888 my ($vmid, $deviceid) = @_;
3890 for (my $i = 0; $i <= 5; $i++) {
3891 my $devices_list = vm_devices_list($vmid);
3892 return 1 if defined($devices_list->{$deviceid});
3896 die "error on hotplug device
'$deviceid'\n";
3900 sub qemu_devicedelverify {
3901 my ($vmid, $deviceid) = @_;
3903 # need to verify that the device is correctly removed as device_del
3904 # is async and empty return is not reliable
3906 for (my $i = 0; $i <= 5; $i++) {
3907 my $devices_list = vm_devices_list($vmid);
3908 return 1 if !defined($devices_list->{$deviceid});
3912 die "error on hot-unplugging device
'$deviceid'\n";
3915 sub qemu_findorcreatescsihw {
3916 my ($storecfg, $conf, $vmid, $device) = @_;
3918 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3920 my $scsihwid="$controller_prefix$controller";
3921 my $devices_list = vm_devices_list($vmid);
3923 if(!defined($devices_list->{$scsihwid})) {
3924 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3930 sub qemu_deletescsihw {
3931 my ($conf, $vmid, $opt) = @_;
3933 my $device = parse_drive($opt, $conf->{$opt});
3935 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3936 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3940 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3942 my $devices_list = vm_devices_list($vmid);
3943 foreach my $opt (keys %{$devices_list}) {
3944 if (PVE::QemuServer::is_valid_drivename($opt)) {
3945 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3946 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3952 my $scsihwid="scsihw
$controller";
3954 vm_deviceunplug($vmid, $conf, $scsihwid);
3959 sub qemu_add_pci_bridge {
3960 my ($storecfg, $conf, $vmid, $device) = @_;
3966 print_pci_addr($device, $bridges);
3968 while (my ($k, $v) = each %$bridges) {
3971 return 1 if !defined($bridgeid) || $bridgeid < 1;
3973 my $bridge = "pci
.$bridgeid";
3974 my $devices_list = vm_devices_list($vmid);
3976 if (!defined($devices_list->{$bridge})) {
3977 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3983 sub qemu_set_link_status {
3984 my ($vmid, $device, $up) = @_;
3986 vm_mon_cmd($vmid, "set_link
", name => $device,
3987 up => $up ? JSON::true : JSON::false);
3990 sub qemu_netdevadd {
3991 my ($vmid, $conf, $device, $deviceid) = @_;
3993 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3994 my %options = split(/[=,]/, $netdev);
3996 vm_mon_cmd($vmid, "netdev_add
", %options);
4000 sub qemu_netdevdel {
4001 my ($vmid, $deviceid) = @_;
4003 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4006 sub qemu_usb_hotplug {
4007 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4011 # remove the old one first
4012 vm_deviceunplug($vmid, $conf, $deviceid);
4014 # check if xhci controller is necessary and available
4015 if ($device->{usb3}) {
4017 my $devicelist = vm_devices_list($vmid);
4019 if (!$devicelist->{xhci}) {
4020 my $pciaddr = print_pci_addr("xhci
");
4021 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4024 my $d = parse_usb_device($device->{host});
4025 $d->{usb3} = $device->{usb3};
4028 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4031 sub qemu_cpu_hotplug {
4032 my ($vmid, $conf, $vcpus) = @_;
4034 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4037 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4038 $sockets = $conf->{sockets} if $conf->{sockets};
4039 my $cores = $conf->{cores} || 1;
4040 my $maxcpus = $sockets * $cores;
4042 $vcpus = $maxcpus if !$vcpus;
4044 die "you can
't add more vcpus than maxcpus\n"
4045 if $vcpus > $maxcpus;
4047 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4049 if ($vcpus < $currentvcpus) {
4051 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4053 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4054 qemu_devicedel($vmid, "cpu$i");
4056 my $currentrunningvcpus = undef;
4058 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4059 last if scalar(@{$currentrunningvcpus}) == $i-1;
4060 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4064 #update conf after each succesfull cpu unplug
4065 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4066 PVE::QemuConfig->write_config($vmid, $conf);
4069 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4075 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4076 die "vcpus in running vm does not match its configuration\n"
4077 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4079 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4081 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4082 my $cpustr = print_cpu_device($conf, $i);
4083 qemu_deviceadd($vmid, $cpustr);
4086 my $currentrunningvcpus = undef;
4088 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4089 last if scalar(@{$currentrunningvcpus}) == $i;
4090 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4094 #update conf after each succesfull cpu hotplug
4095 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4096 PVE::QemuConfig->write_config($vmid, $conf);
4100 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4101 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4106 sub qemu_block_set_io_throttle {
4107 my ($vmid, $deviceid,
4108 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4109 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4110 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4111 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4113 return if !check_running($vmid) ;
4115 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4117 bps_rd => int($bps_rd),
4118 bps_wr => int($bps_wr),
4120 iops_rd => int($iops_rd),
4121 iops_wr => int($iops_wr),
4122 bps_max => int($bps_max),
4123 bps_rd_max => int($bps_rd_max),
4124 bps_wr_max => int($bps_wr_max),
4125 iops_max => int($iops_max),
4126 iops_rd_max => int($iops_rd_max),
4127 iops_wr_max => int($iops_wr_max),
4128 bps_max_length => int($bps_max_length),
4129 bps_rd_max_length => int($bps_rd_max_length),
4130 bps_wr_max_length => int($bps_wr_max_length),
4131 iops_max_length => int($iops_max_length),
4132 iops_rd_max_length => int($iops_rd_max_length),
4133 iops_wr_max_length => int($iops_wr_max_length),
4138 # old code, only used to shutdown old VM after update
4140 my ($fh, $timeout) = @_;
4142 my $sel = new IO::Select;
4149 while (scalar (@ready = $sel->can_read($timeout))) {
4151 if ($count = $fh->sysread($buf, 8192)) {
4152 if ($buf =~ /^(.*)\(qemu\) $/s) {
4159 if (!defined($count)) {
4166 die "monitor read timeout\n" if !scalar(@ready);
4171 sub qemu_block_resize {
4172 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4174 my $running = check_running($vmid);
4176 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4178 return if !$running;
4180 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4184 sub qemu_volume_snapshot {
4185 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4187 my $running = check_running($vmid);
4189 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4190 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4192 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4196 sub qemu_volume_snapshot_delete {
4197 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4199 my $running = check_running($vmid);
4201 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4202 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4204 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4208 sub set_migration_caps {
4214 "auto-converge" => 1,
4216 "x-rdma-pin-all" => 0,
4221 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4223 for my $supported_capability (@$supported_capabilities) {
4225 capability => $supported_capability->{capability},
4226 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4230 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4233 my $fast_plug_option = {
4241 'vmstatestorage
' => 1,
4244 # hotplug changes in [PENDING]
4245 # $selection hash can be used to only apply specified options, for
4246 # example: { cores => 1 } (only apply changed 'cores
')
4247 # $errors ref is used to return error messages
4248 sub vmconfig_hotplug_pending {
4249 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4251 my $defaults = load_defaults();
4253 # commit values which do not have any impact on running VM first
4254 # Note: those option cannot raise errors, we we do not care about
4255 # $selection and always apply them.
4257 my $add_error = sub {
4258 my ($opt, $msg) = @_;
4259 $errors->{$opt} = "hotplug problem - $msg";
4263 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4264 if ($fast_plug_option->{$opt}) {
4265 $conf->{$opt} = $conf->{pending}->{$opt};
4266 delete $conf->{pending}->{$opt};
4272 PVE::QemuConfig->write_config($vmid, $conf);
4273 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4276 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4278 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4279 while (my ($opt, $force) = each %$pending_delete_hash) {
4280 next if $selection && !$selection->{$opt};
4282 if ($opt eq 'hotplug
') {
4283 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4284 } elsif ($opt eq 'tablet
') {
4285 die "skip\n" if !$hotplug_features->{usb};
4286 if ($defaults->{tablet}) {
4287 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4289 vm_deviceunplug($vmid, $conf, $opt);
4291 } elsif ($opt =~ m/^usb\d+/) {
4293 # since we cannot reliably hot unplug usb devices
4294 # we are disabling it
4295 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4296 vm_deviceunplug($vmid, $conf, $opt);
4297 } elsif ($opt eq 'vcpus
') {
4298 die "skip\n" if !$hotplug_features->{cpu};
4299 qemu_cpu_hotplug($vmid, $conf, undef);
4300 } elsif ($opt eq 'balloon
') {
4301 # enable balloon device is not hotpluggable
4302 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4303 } elsif ($fast_plug_option->{$opt}) {
4305 } elsif ($opt =~ m/^net(\d+)$/) {
4306 die "skip\n" if !$hotplug_features->{network};
4307 vm_deviceunplug($vmid, $conf, $opt);
4308 } elsif (is_valid_drivename($opt)) {
4309 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4310 vm_deviceunplug($vmid, $conf, $opt);
4311 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4312 } elsif ($opt =~ m/^memory$/) {
4313 die "skip\n" if !$hotplug_features->{memory};
4314 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4315 } elsif ($opt eq 'cpuunits
') {
4316 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4317 } elsif ($opt eq 'cpulimit
') {
4318 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4324 &$add_error($opt, $err) if $err ne "skip\n";
4326 # save new config if hotplug was successful
4327 delete $conf->{$opt};
4328 vmconfig_undelete_pending_option($conf, $opt);
4329 PVE::QemuConfig->write_config($vmid, $conf);
4330 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4334 my $apply_pending_cloudinit;
4335 $apply_pending_cloudinit = sub {
4336 my ($key, $value) = @_;
4337 $apply_pending_cloudinit = sub {}; # once is enough
4339 my @cloudinit_opts = keys %$confdesc_cloudinit;
4340 foreach my $opt (keys %{$conf->{pending}}) {
4341 next if !grep { $_ eq $opt } @cloudinit_opts;
4342 $conf->{$opt} = delete $conf->{pending}->{$opt};
4345 my $new_conf = { %$conf };
4346 $new_conf->{$key} = $value;
4347 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4350 foreach my $opt (keys %{$conf->{pending}}) {
4351 next if $selection && !$selection->{$opt};
4352 my $value = $conf->{pending}->{$opt};
4354 if ($opt eq 'hotplug
') {
4355 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4356 } elsif ($opt eq 'tablet
') {
4357 die "skip\n" if !$hotplug_features->{usb};
4359 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4360 } elsif ($value == 0) {
4361 vm_deviceunplug($vmid, $conf, $opt);
4363 } elsif ($opt =~ m/^usb\d+$/) {
4365 # since we cannot reliably hot unplug usb devices
4366 # we are disabling it
4367 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4368 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4369 die "skip\n" if !$d;
4370 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4371 } elsif ($opt eq 'vcpus
') {
4372 die "skip\n" if !$hotplug_features->{cpu};
4373 qemu_cpu_hotplug($vmid, $conf, $value);
4374 } elsif ($opt eq 'balloon
') {
4375 # enable/disable balloning device is not hotpluggable
4376 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4377 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4378 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4380 # allow manual ballooning if shares is set to zero
4381 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4382 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4383 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4385 } elsif ($opt =~ m/^net(\d+)$/) {
4386 # some changes can be done without hotplug
4387 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4388 $vmid, $opt, $value);
4389 } elsif (is_valid_drivename($opt)) {
4390 # some changes can be done without hotplug
4391 my $drive = parse_drive($opt, $value);
4392 if (drive_is_cloudinit($drive)) {
4393 &$apply_pending_cloudinit($opt, $value);
4395 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4396 $vmid, $opt, $value, 1);
4397 } elsif ($opt =~ m/^memory$/) { #dimms
4398 die "skip\n" if !$hotplug_features->{memory};
4399 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4400 } elsif ($opt eq 'cpuunits
') {
4401 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4402 } elsif ($opt eq 'cpulimit
') {
4403 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4404 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4406 die "skip\n"; # skip non-hot-pluggable options
4410 &$add_error($opt, $err) if $err ne "skip\n";
4412 # save new config if hotplug was successful
4413 $conf->{$opt} = $value;
4414 delete $conf->{pending}->{$opt};
4415 PVE::QemuConfig->write_config($vmid, $conf);
4416 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4421 sub try_deallocate_drive {
4422 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4424 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4425 my $volid = $drive->{file};
4426 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4427 my $sid = PVE::Storage::parse_volume_id($volid);
4428 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4430 # check if the disk is really unused
4431 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4432 if is_volume_in_use($storecfg, $conf, $key, $volid);
4433 PVE::Storage::vdisk_free($storecfg, $volid);
4436 # If vm is not owner of this disk remove from config
4444 sub vmconfig_delete_or_detach_drive {
4445 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4447 my $drive = parse_drive($opt, $conf->{$opt});
4449 my $rpcenv = PVE::RPCEnvironment::get();
4450 my $authuser = $rpcenv->get_user();
4453 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4454 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4456 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4460 sub vmconfig_apply_pending {
4461 my ($vmid, $conf, $storecfg) = @_;
4465 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4466 while (my ($opt, $force) = each %$pending_delete_hash) {
4467 die "internal error" if $opt =~ m/^unused/;
4468 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4469 if (!defined($conf->{$opt})) {
4470 vmconfig_undelete_pending_option($conf, $opt);
4471 PVE::QemuConfig->write_config($vmid, $conf);
4472 } elsif (is_valid_drivename($opt)) {
4473 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4474 vmconfig_undelete_pending_option($conf, $opt);
4475 delete $conf->{$opt};
4476 PVE::QemuConfig->write_config($vmid, $conf);
4478 vmconfig_undelete_pending_option($conf, $opt);
4479 delete $conf->{$opt};
4480 PVE::QemuConfig->write_config($vmid, $conf);
4484 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4486 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4487 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4489 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4490 # skip if nothing changed
4491 } elsif (is_valid_drivename($opt)) {
4492 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4493 if defined($conf->{$opt});
4494 $conf->{$opt} = $conf->{pending}->{$opt};
4496 $conf->{$opt} = $conf->{pending}->{$opt};
4499 delete $conf->{pending}->{$opt};
4500 PVE::QemuConfig->write_config($vmid, $conf);
4504 my $safe_num_ne = sub {
4507 return 0 if !defined($a) && !defined($b);
4508 return 1 if !defined($a);
4509 return 1 if !defined($b);
4514 my $safe_string_ne = sub {
4517 return 0 if !defined($a) && !defined($b);
4518 return 1 if !defined($a);
4519 return 1 if !defined($b);
4524 sub vmconfig_update_net {
4525 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4527 my $newnet = parse_net($value);
4529 if ($conf->{$opt}) {
4530 my $oldnet = parse_net($conf->{$opt});
4532 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4533 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4534 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4535 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4537 # for non online change, we try to hot-unplug
4538 die "skip\n" if !$hotplug;
4539 vm_deviceunplug($vmid, $conf, $opt);
4542 die "internal error" if $opt !~ m/net(\d+)/;
4543 my $iface = "tap${vmid}i$1";
4545 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4546 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4547 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4548 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4549 PVE::Network::tap_unplug($iface);
4550 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4551 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4552 # Rate can be applied on its own but any change above needs to
4553 # include the rate in tap_plug since OVS resets everything.
4554 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4557 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4558 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4566 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4572 sub vmconfig_update_disk {
4573 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4575 # fixme: do we need force?
4577 my $drive = parse_drive($opt, $value);
4579 if ($conf->{$opt}) {
4581 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4583 my $media = $drive->{media} || 'disk
';
4584 my $oldmedia = $old_drive->{media} || 'disk
';
4585 die "unable to change media type\n" if $media ne $oldmedia;
4587 if (!drive_is_cdrom($old_drive)) {
4589 if ($drive->{file} ne $old_drive->{file}) {
4591 die "skip\n" if !$hotplug;
4593 # unplug and register as unused
4594 vm_deviceunplug($vmid, $conf, $opt);
4595 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4598 # update existing disk
4600 # skip non hotpluggable value
4601 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4602 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4603 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4604 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4609 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4610 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4611 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4612 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4613 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4614 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4615 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4616 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4617 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4618 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4619 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4620 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4621 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4622 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4623 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4624 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4625 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4626 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4628 qemu_block_set_io_throttle($vmid,"drive-$opt",
4629 ($drive->{mbps} || 0)*1024*1024,
4630 ($drive->{mbps_rd} || 0)*1024*1024,
4631 ($drive->{mbps_wr} || 0)*1024*1024,
4632 $drive->{iops} || 0,
4633 $drive->{iops_rd} || 0,
4634 $drive->{iops_wr} || 0,
4635 ($drive->{mbps_max} || 0)*1024*1024,
4636 ($drive->{mbps_rd_max} || 0)*1024*1024,
4637 ($drive->{mbps_wr_max} || 0)*1024*1024,
4638 $drive->{iops_max} || 0,
4639 $drive->{iops_rd_max} || 0,
4640 $drive->{iops_wr_max} || 0,
4641 $drive->{bps_max_length} || 1,
4642 $drive->{bps_rd_max_length} || 1,
4643 $drive->{bps_wr_max_length} || 1,
4644 $drive->{iops_max_length} || 1,
4645 $drive->{iops_rd_max_length} || 1,
4646 $drive->{iops_wr_max_length} || 1);
4655 if ($drive->{file} eq 'none
') {
4656 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4657 if (drive_is_cloudinit($old_drive)) {
4658 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4661 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4662 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4663 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4671 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4673 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4674 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4678 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4679 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4681 PVE::QemuConfig->lock_config($vmid, sub {
4682 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4684 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4686 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4688 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4690 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4691 vmconfig_apply_pending($vmid, $conf, $storecfg);
4692 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4695 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4697 my $defaults = load_defaults();
4699 # set environment variable useful inside network script
4700 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4702 my $local_volumes = {};
4704 if ($targetstorage) {
4705 foreach_drive($conf, sub {
4706 my ($ds, $drive) = @_;
4708 return if drive_is_cdrom($drive);
4710 my $volid = $drive->{file};
4714 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4716 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4717 return if $scfg->{shared};
4718 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4723 foreach my $opt (sort keys %$local_volumes) {
4725 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4726 my $drive = parse_drive($opt, $conf->{$opt});
4728 #if remote storage is specified, use default format
4729 if ($targetstorage && $targetstorage ne "1") {
4730 $storeid = $targetstorage;
4731 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4732 $format = $defFormat;
4734 #else we use same format than original
4735 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4736 $format = qemu_img_format($scfg, $volid);
4739 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4740 my $newdrive = $drive;
4741 $newdrive->{format} = $format;
4742 $newdrive->{file} = $newvolid;
4743 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4744 $local_volumes->{$opt} = $drivestr;
4745 #pass drive to conf for command line
4746 $conf->{$opt} = $drivestr;
4750 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4752 my $migrate_port = 0;
4755 if ($statefile eq 'tcp
') {
4756 my $localip = "localhost";
4757 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4758 my $nodename = PVE::INotify::nodename();
4760 if (!defined($migration_type)) {
4761 if (defined($datacenterconf->{migration}->{type})) {
4762 $migration_type = $datacenterconf->{migration}->{type};
4764 $migration_type = 'secure
';
4768 if ($migration_type eq 'insecure
') {
4769 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4770 if ($migrate_network_addr) {
4771 $localip = $migrate_network_addr;
4773 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4776 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4779 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4780 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4781 $migrate_uri = "tcp:${localip}:${migrate_port}";
4782 push @$cmd, '-incoming
', $migrate_uri;
4785 } elsif ($statefile eq 'unix
') {
4786 # should be default for secure migrations as a ssh TCP forward
4787 # tunnel is not deterministic reliable ready and fails regurarly
4788 # to set up in time, so use UNIX socket forwards
4789 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4790 unlink $socket_addr;
4792 $migrate_uri = "unix:$socket_addr";
4794 push @$cmd, '-incoming
', $migrate_uri;
4798 push @$cmd, '-loadstate
', $statefile;
4805 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4806 my $d = parse_hostpci($conf->{"hostpci$i"});
4808 my $pcidevices = $d->{pciid};
4809 foreach my $pcidevice (@$pcidevices) {
4810 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4812 my $info = pci_device_info("0000:$pciid");
4813 die "IOMMU not present\n" if !check_iommu_support();
4814 die "no pci device info for device '$pciid'\n" if !$info;
4815 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4816 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4820 PVE::Storage::activate_volumes($storecfg, $vollist);
4822 if (!check_running($vmid, 1)) {
4824 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4825 outfunc => sub {}, errfunc => sub {});
4829 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4830 : $defaults->{cpuunits};
4832 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4833 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4836 Slice => 'qemu
.slice
',
4838 CPUShares => $cpuunits
4841 if (my $cpulimit = $conf->{cpulimit}) {
4842 $properties{CPUQuota} = int($cpulimit * 100);
4844 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4846 if ($conf->{hugepages}) {
4849 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4850 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4852 PVE::QemuServer::Memory::hugepages_mount();
4853 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4856 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4857 run_command($cmd, %run_params);
4861 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4865 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4867 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4871 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4872 run_command($cmd, %run_params);
4877 # deactivate volumes if start fails
4878 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4879 die "start failed: $err";
4882 print "migration listens on $migrate_uri\n" if $migrate_uri;
4884 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4885 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4889 #start nbd server for storage migration
4890 if ($targetstorage) {
4891 my $nodename = PVE::INotify::nodename();
4892 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4893 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4894 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4895 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4897 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4899 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4901 foreach my $opt (sort keys %$local_volumes) {
4902 my $volid = $local_volumes->{$opt};
4903 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4904 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4905 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4909 if ($migratedfrom) {
4911 set_migration_caps($vmid);
4916 print "spice listens on port $spice_port\n";
4917 if ($spice_ticket) {
4918 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4919 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4924 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4925 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4926 if $conf->{balloon};
4929 foreach my $opt (keys %$conf) {
4930 next if $opt !~ m/^net\d+$/;
4931 my $nicconf = parse_net($conf->{$opt});
4932 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4936 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4937 path => "machine/peripheral/balloon0",
4938 property => "guest-stats-polling-interval",
4939 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4945 my ($vmid, $execute, %params) = @_;
4947 my $cmd = { execute => $execute, arguments => \%params };
4948 vm_qmp_command($vmid, $cmd);
4951 sub vm_mon_cmd_nocheck {
4952 my ($vmid, $execute, %params) = @_;
4954 my $cmd = { execute => $execute, arguments => \%params };
4955 vm_qmp_command($vmid, $cmd, 1);
4958 sub vm_qmp_command {
4959 my ($vmid, $cmd, $nocheck) = @_;
4964 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4965 $timeout = $cmd->{arguments}->{timeout};
4966 delete $cmd->{arguments}->{timeout};
4970 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4971 my $sname = qmp_socket($vmid);
4972 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4973 my $qmpclient = PVE::QMPClient->new();
4975 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4977 die "unable to open monitor socket\n";
4981 syslog("err", "VM $vmid qmp command failed - $err");
4988 sub vm_human_monitor_command {
4989 my ($vmid, $cmdline) = @_;
4994 execute => 'human-monitor-command
',
4995 arguments => { 'command-line
' => $cmdline},
4998 return vm_qmp_command($vmid, $cmd);
5001 sub vm_commandline {
5002 my ($storecfg, $vmid) = @_;
5004 my $conf = PVE::QemuConfig->load_config($vmid);
5006 my $defaults = load_defaults();
5008 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5010 return PVE::Tools::cmd2string($cmd);
5014 my ($vmid, $skiplock) = @_;
5016 PVE::QemuConfig->lock_config($vmid, sub {
5018 my $conf = PVE::QemuConfig->load_config($vmid);
5020 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5022 vm_mon_cmd($vmid, "system_reset");
5026 sub get_vm_volumes {
5030 foreach_volid($conf, sub {
5031 my ($volid, $attr) = @_;
5033 return if $volid =~ m|^/|;
5035 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5038 push @$vollist, $volid;
5044 sub vm_stop_cleanup {
5045 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5050 my $vollist = get_vm_volumes($conf);
5051 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5054 foreach my $ext (qw(mon qmp pid vnc qga)) {
5055 unlink "/var/run/qemu-server/${vmid}.$ext";
5058 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5060 warn $@ if $@; # avoid errors - just warn
5063 # Note: use $nockeck to skip tests if VM configuration file exists.
5064 # We need that when migration VMs to other nodes (files already moved)
5065 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5067 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5069 $force = 1 if !defined($force) && !$shutdown;
5072 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5073 kill 15, $pid if $pid;
5074 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5075 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5079 PVE
::QemuConfig-
>lock_config($vmid, sub {
5081 my $pid = check_running
($vmid, $nocheck);
5086 $conf = PVE
::QemuConfig-
>load_config($vmid);
5087 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5088 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5089 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5090 $timeout = $opts->{down
} if $opts->{down
};
5094 $timeout = 60 if !defined($timeout);
5098 if (defined($conf) && $conf->{agent
}) {
5099 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5101 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5104 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5111 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5116 if ($count >= $timeout) {
5118 warn "VM still running - terminating now with SIGTERM\n";
5121 die "VM quit/powerdown failed - got timeout\n";
5124 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5129 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5132 die "VM quit/powerdown failed\n";
5140 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5145 if ($count >= $timeout) {
5146 warn "VM still running - terminating now with SIGKILL\n";
5151 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5156 my ($vmid, $skiplock) = @_;
5158 PVE
::QemuConfig-
>lock_config($vmid, sub {
5160 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5162 PVE
::QemuConfig-
>check_lock($conf)
5163 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5165 vm_mon_cmd
($vmid, "stop");
5170 my ($vmid, $skiplock, $nocheck) = @_;
5172 PVE
::QemuConfig-
>lock_config($vmid, sub {
5176 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5178 PVE
::QemuConfig-
>check_lock($conf)
5179 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5181 vm_mon_cmd
($vmid, "cont");
5184 vm_mon_cmd_nocheck
($vmid, "cont");
5190 my ($vmid, $skiplock, $key) = @_;
5192 PVE
::QemuConfig-
>lock_config($vmid, sub {
5194 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5196 # there is no qmp command, so we use the human monitor command
5197 vm_human_monitor_command
($vmid, "sendkey $key");
5202 my ($storecfg, $vmid, $skiplock) = @_;
5204 PVE
::QemuConfig-
>lock_config($vmid, sub {
5206 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5208 if (!check_running
($vmid)) {
5209 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5211 die "VM $vmid is running - destroy failed\n";
5219 my ($filename, $buf) = @_;
5221 my $fh = IO
::File-
>new($filename, "w");
5222 return undef if !$fh;
5224 my $res = print $fh $buf;
5231 sub pci_device_info
{
5236 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5237 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5239 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5240 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5242 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5243 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5245 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5246 return undef if !defined($product) || $product !~ s/^0x//;
5251 product
=> $product,
5257 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5266 my $name = $dev->{name
};
5268 my $fn = "$pcisysfs/devices/$name/reset";
5270 return file_write
($fn, "1");
5273 sub pci_dev_bind_to_vfio
{
5276 my $name = $dev->{name
};
5278 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5280 if (!-d
$vfio_basedir) {
5281 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5283 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5285 my $testdir = "$vfio_basedir/$name";
5286 return 1 if -d
$testdir;
5288 my $data = "$dev->{vendor} $dev->{product}";
5289 return undef if !file_write
("$vfio_basedir/new_id", $data);
5291 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5292 if (!file_write
($fn, $name)) {
5293 return undef if -f
$fn;
5296 $fn = "$vfio_basedir/bind";
5297 if (! -d
$testdir) {
5298 return undef if !file_write
($fn, $name);
5304 sub pci_dev_group_bind_to_vfio
{
5307 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5309 if (!-d
$vfio_basedir) {
5310 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5312 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5314 # get IOMMU group devices
5315 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5316 my @devs = grep /^0000:/, readdir($D);
5319 foreach my $pciid (@devs) {
5320 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5322 # pci bridges, switches or root ports are not supported
5323 # they have a pci_bus subdirectory so skip them
5324 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5326 my $info = pci_device_info
($1);
5327 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5333 # vzdump restore implementaion
5335 sub tar_archive_read_firstfile
{
5336 my $archive = shift;
5338 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5340 # try to detect archive type first
5341 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5342 die "unable to open file '$archive'\n";
5343 my $firstfile = <$fh>;
5347 die "ERROR: archive contaions no data\n" if !$firstfile;
5353 sub tar_restore_cleanup
{
5354 my ($storecfg, $statfile) = @_;
5356 print STDERR
"starting cleanup\n";
5358 if (my $fd = IO
::File-
>new($statfile, "r")) {
5359 while (defined(my $line = <$fd>)) {
5360 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5363 if ($volid =~ m
|^/|) {
5364 unlink $volid || die 'unlink failed\n';
5366 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5368 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5370 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5372 print STDERR
"unable to parse line in statfile - $line";
5379 sub restore_archive
{
5380 my ($archive, $vmid, $user, $opts) = @_;
5382 my $format = $opts->{format
};
5385 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5386 $format = 'tar' if !$format;
5388 } elsif ($archive =~ m/\.tar$/) {
5389 $format = 'tar' if !$format;
5390 } elsif ($archive =~ m/.tar.lzo$/) {
5391 $format = 'tar' if !$format;
5393 } elsif ($archive =~ m/\.vma$/) {
5394 $format = 'vma' if !$format;
5395 } elsif ($archive =~ m/\.vma\.gz$/) {
5396 $format = 'vma' if !$format;
5398 } elsif ($archive =~ m/\.vma\.lzo$/) {
5399 $format = 'vma' if !$format;
5402 $format = 'vma' if !$format; # default
5405 # try to detect archive format
5406 if ($format eq 'tar') {
5407 return restore_tar_archive
($archive, $vmid, $user, $opts);
5409 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5413 sub restore_update_config_line
{
5414 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5416 return if $line =~ m/^\#qmdump\#/;
5417 return if $line =~ m/^\#vzdump\#/;
5418 return if $line =~ m/^lock:/;
5419 return if $line =~ m/^unused\d+:/;
5420 return if $line =~ m/^parent:/;
5421 return if $line =~ m/^template:/; # restored VM is never a template
5423 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5424 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5425 # try to convert old 1.X settings
5426 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5427 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5428 my ($model, $macaddr) = split(/\=/, $devconfig);
5429 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5432 bridge
=> "vmbr$ind",
5433 macaddr
=> $macaddr,
5435 my $netstr = print_net
($net);
5437 print $outfd "net$cookie->{netcount}: $netstr\n";
5438 $cookie->{netcount
}++;
5440 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5441 my ($id, $netstr) = ($1, $2);
5442 my $net = parse_net
($netstr);
5443 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5444 $netstr = print_net
($net);
5445 print $outfd "$id: $netstr\n";
5446 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5449 my $di = parse_drive
($virtdev, $value);
5450 if (defined($di->{backup
}) && !$di->{backup
}) {
5451 print $outfd "#$line";
5452 } elsif ($map->{$virtdev}) {
5453 delete $di->{format
}; # format can change on restore
5454 $di->{file
} = $map->{$virtdev};
5455 $value = print_drive
($vmid, $di);
5456 print $outfd "$virtdev: $value\n";
5460 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5461 my ($uuid, $uuid_str);
5462 UUID
::generate
($uuid);
5463 UUID
::unparse
($uuid, $uuid_str);
5464 my $smbios1 = parse_smbios1
($2);
5465 $smbios1->{uuid
} = $uuid_str;
5466 print $outfd $1.print_smbios1
($smbios1)."\n";
5473 my ($cfg, $vmid) = @_;
5475 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5477 my $volid_hash = {};
5478 foreach my $storeid (keys %$info) {
5479 foreach my $item (@{$info->{$storeid}}) {
5480 next if !($item->{volid
} && $item->{size
});
5481 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5482 $volid_hash->{$item->{volid
}} = $item;
5489 sub is_volume_in_use
{
5490 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5492 my $path = PVE
::Storage
::path
($storecfg, $volid);
5494 my $scan_config = sub {
5495 my ($cref, $snapname) = @_;
5497 foreach my $key (keys %$cref) {
5498 my $value = $cref->{$key};
5499 if (is_valid_drivename
($key)) {
5500 next if $skip_drive && $key eq $skip_drive;
5501 my $drive = parse_drive
($key, $value);
5502 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5503 return 1 if $volid eq $drive->{file
};
5504 if ($drive->{file
} =~ m!^/!) {
5505 return 1 if $drive->{file
} eq $path;
5507 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5509 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5511 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5519 return 1 if &$scan_config($conf);
5523 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5524 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5530 sub update_disksize
{
5531 my ($vmid, $conf, $volid_hash) = @_;
5535 # used and unused disks
5536 my $referenced = {};
5538 # Note: it is allowed to define multiple storages with same path (alias), so
5539 # we need to check both 'volid' and real 'path' (two different volid can point
5540 # to the same path).
5542 my $referencedpath = {};
5545 foreach my $opt (keys %$conf) {
5546 if (is_valid_drivename
($opt)) {
5547 my $drive = parse_drive
($opt, $conf->{$opt});
5548 my $volid = $drive->{file
};
5551 $referenced->{$volid} = 1;
5552 if ($volid_hash->{$volid} &&
5553 (my $path = $volid_hash->{$volid}->{path
})) {
5554 $referencedpath->{$path} = 1;
5557 next if drive_is_cdrom
($drive);
5558 next if !$volid_hash->{$volid};
5560 $drive->{size
} = $volid_hash->{$volid}->{size
};
5561 my $new = print_drive
($vmid, $drive);
5562 if ($new ne $conf->{$opt}) {
5564 $conf->{$opt} = $new;
5569 # remove 'unusedX' entry if volume is used
5570 foreach my $opt (keys %$conf) {
5571 next if $opt !~ m/^unused\d+$/;
5572 my $volid = $conf->{$opt};
5573 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5574 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5576 delete $conf->{$opt};
5579 $referenced->{$volid} = 1;
5580 $referencedpath->{$path} = 1 if $path;
5583 foreach my $volid (sort keys %$volid_hash) {
5584 next if $volid =~ m/vm-$vmid-state-/;
5585 next if $referenced->{$volid};
5586 my $path = $volid_hash->{$volid}->{path
};
5587 next if !$path; # just to be sure
5588 next if $referencedpath->{$path};
5590 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5591 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5598 my ($vmid, $nolock) = @_;
5600 my $cfg = PVE
::Storage
::config
();
5602 my $volid_hash = scan_volids
($cfg, $vmid);
5604 my $updatefn = sub {
5607 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5609 PVE
::QemuConfig-
>check_lock($conf);
5612 foreach my $volid (keys %$volid_hash) {
5613 my $info = $volid_hash->{$volid};
5614 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5617 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5619 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5622 if (defined($vmid)) {
5626 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5629 my $vmlist = config_list
();
5630 foreach my $vmid (keys %$vmlist) {
5634 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5640 sub restore_vma_archive
{
5641 my ($archive, $vmid, $user, $opts, $comp) = @_;
5643 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5644 my $readfrom = $archive;
5649 my $qarchive = PVE
::Tools
::shellquote
($archive);
5650 if ($comp eq 'gzip') {
5651 $uncomp = "zcat $qarchive|";
5652 } elsif ($comp eq 'lzop') {
5653 $uncomp = "lzop -d -c $qarchive|";
5655 die "unknown compression method '$comp'\n";
5660 my $tmpdir = "/var/tmp/vzdumptmp$$";
5663 # disable interrupts (always do cleanups)
5667 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5669 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5670 POSIX
::mkfifo
($mapfifo, 0600);
5673 my $openfifo = sub {
5674 open($fifofh, '>', $mapfifo) || die $!;
5677 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5684 my $rpcenv = PVE
::RPCEnvironment
::get
();
5686 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5687 my $tmpfn = "$conffile.$$.tmp";
5689 # Note: $oldconf is undef if VM does not exists
5690 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5691 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5693 my $print_devmap = sub {
5694 my $virtdev_hash = {};
5696 my $cfgfn = "$tmpdir/qemu-server.conf";
5698 # we can read the config - that is already extracted
5699 my $fh = IO
::File-
>new($cfgfn, "r") ||
5700 "unable to read qemu-server.conf - $!\n";
5702 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5704 my $pve_firewall_dir = '/etc/pve/firewall';
5705 mkdir $pve_firewall_dir; # make sure the dir exists
5706 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5709 while (defined(my $line = <$fh>)) {
5710 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5711 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5712 die "archive does not contain data for drive '$virtdev'\n"
5713 if !$devinfo->{$devname};
5714 if (defined($opts->{storage
})) {
5715 $storeid = $opts->{storage
} || 'local';
5716 } elsif (!$storeid) {
5719 $format = 'raw' if !$format;
5720 $devinfo->{$devname}->{devname
} = $devname;
5721 $devinfo->{$devname}->{virtdev
} = $virtdev;
5722 $devinfo->{$devname}->{format
} = $format;
5723 $devinfo->{$devname}->{storeid
} = $storeid;
5725 # check permission on storage
5726 my $pool = $opts->{pool
}; # todo: do we need that?
5727 if ($user ne 'root@pam') {
5728 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5731 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5735 foreach my $devname (keys %$devinfo) {
5736 die "found no device mapping information for device '$devname'\n"
5737 if !$devinfo->{$devname}->{virtdev
};
5740 my $cfg = PVE
::Storage
::config
();
5742 # create empty/temp config
5744 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5745 foreach_drive
($oldconf, sub {
5746 my ($ds, $drive) = @_;
5748 return if drive_is_cdrom
($drive);
5750 my $volid = $drive->{file
};
5752 return if !$volid || $volid =~ m
|^/|;
5754 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5755 return if !$path || !$owner || ($owner != $vmid);
5757 # Note: only delete disk we want to restore
5758 # other volumes will become unused
5759 if ($virtdev_hash->{$ds}) {
5760 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5767 # delete vmstate files
5768 # since after the restore we have no snapshots anymore
5769 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5770 my $snap = $oldconf->{snapshots
}->{$snapname};
5771 if ($snap->{vmstate
}) {
5772 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5781 foreach my $virtdev (sort keys %$virtdev_hash) {
5782 my $d = $virtdev_hash->{$virtdev};
5783 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5784 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5786 # test if requested format is supported
5787 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5788 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5789 $d->{format
} = $defFormat if !$supported;
5791 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5792 $d->{format
}, undef, $alloc_size);
5793 print STDERR
"new volume ID is '$volid'\n";
5794 $d->{volid
} = $volid;
5795 my $path = PVE
::Storage
::path
($cfg, $volid);
5797 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5799 my $write_zeros = 1;
5800 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5804 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5806 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5807 $map->{$virtdev} = $volid;
5810 $fh->seek(0, 0) || die "seek failed - $!\n";
5812 my $outfd = new IO
::File
($tmpfn, "w") ||
5813 die "unable to write config for VM $vmid\n";
5815 my $cookie = { netcount
=> 0 };
5816 while (defined(my $line = <$fh>)) {
5817 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5830 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5831 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5833 $oldtimeout = alarm($timeout);
5840 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5841 my ($dev_id, $size, $devname) = ($1, $2, $3);
5842 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5843 } elsif ($line =~ m/^CTIME: /) {
5844 # we correctly received the vma config, so we can disable
5845 # the timeout now for disk allocation (set to 10 minutes, so
5846 # that we always timeout if something goes wrong)
5849 print $fifofh "done\n";
5850 my $tmp = $oldtimeout || 0;
5851 $oldtimeout = undef;
5857 print "restore vma archive: $cmd\n";
5858 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5862 alarm($oldtimeout) if $oldtimeout;
5865 foreach my $devname (keys %$devinfo) {
5866 my $volid = $devinfo->{$devname}->{volid
};
5867 push @$vollist, $volid if $volid;
5870 my $cfg = PVE
::Storage
::config
();
5871 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5879 foreach my $devname (keys %$devinfo) {
5880 my $volid = $devinfo->{$devname}->{volid
};
5883 if ($volid =~ m
|^/|) {
5884 unlink $volid || die 'unlink failed\n';
5886 PVE
::Storage
::vdisk_free
($cfg, $volid);
5888 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5890 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5897 rename($tmpfn, $conffile) ||
5898 die "unable to commit configuration file '$conffile'\n";
5900 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5902 eval { rescan
($vmid, 1); };
5906 sub restore_tar_archive
{
5907 my ($archive, $vmid, $user, $opts) = @_;
5909 if ($archive ne '-') {
5910 my $firstfile = tar_archive_read_firstfile
($archive);
5911 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5912 if $firstfile ne 'qemu-server.conf';
5915 my $storecfg = PVE
::Storage
::config
();
5917 # destroy existing data - keep empty config
5918 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5919 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5921 my $tocmd = "/usr/lib/qemu-server/qmextract";
5923 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5924 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5925 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5926 $tocmd .= ' --info' if $opts->{info
};
5928 # tar option "xf" does not autodetect compression when read from STDIN,
5929 # so we pipe to zcat
5930 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5931 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5933 my $tmpdir = "/var/tmp/vzdumptmp$$";
5936 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5937 local $ENV{VZDUMP_VMID
} = $vmid;
5938 local $ENV{VZDUMP_USER
} = $user;
5940 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5941 my $tmpfn = "$conffile.$$.tmp";
5943 # disable interrupts (always do cleanups)
5947 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
5955 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5957 if ($archive eq '-') {
5958 print "extracting archive from STDIN\n";
5959 run_command
($cmd, input
=> "<&STDIN");
5961 print "extracting archive '$archive'\n";
5965 return if $opts->{info
};
5969 my $statfile = "$tmpdir/qmrestore.stat";
5970 if (my $fd = IO
::File-
>new($statfile, "r")) {
5971 while (defined (my $line = <$fd>)) {
5972 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5973 $map->{$1} = $2 if $1;
5975 print STDERR
"unable to parse line in statfile - $line\n";
5981 my $confsrc = "$tmpdir/qemu-server.conf";
5983 my $srcfd = new IO
::File
($confsrc, "r") ||
5984 die "unable to open file '$confsrc'\n";
5986 my $outfd = new IO
::File
($tmpfn, "w") ||
5987 die "unable to write config for VM $vmid\n";
5989 my $cookie = { netcount
=> 0 };
5990 while (defined (my $line = <$srcfd>)) {
5991 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6003 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6010 rename $tmpfn, $conffile ||
6011 die "unable to commit configuration file '$conffile'\n";
6013 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6015 eval { rescan
($vmid, 1); };
6019 sub foreach_storage_used_by_vm
{
6020 my ($conf, $func) = @_;
6024 foreach_drive
($conf, sub {
6025 my ($ds, $drive) = @_;
6026 return if drive_is_cdrom
($drive);
6028 my $volid = $drive->{file
};
6030 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6031 $sidhash->{$sid} = $sid if $sid;
6034 foreach my $sid (sort keys %$sidhash) {
6039 sub do_snapshots_with_qemu
{
6040 my ($storecfg, $volid) = @_;
6042 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6044 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6045 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6049 if ($volid =~ m/\.(qcow2|qed)$/){
6056 sub qga_check_running
{
6059 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6061 warn "Qemu Guest Agent is not running - $@";
6067 sub template_create
{
6068 my ($vmid, $conf, $disk) = @_;
6070 my $storecfg = PVE
::Storage
::config
();
6072 foreach_drive
($conf, sub {
6073 my ($ds, $drive) = @_;
6075 return if drive_is_cdrom
($drive);
6076 return if $disk && $ds ne $disk;
6078 my $volid = $drive->{file
};
6079 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6081 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6082 $drive->{file
} = $voliddst;
6083 $conf->{$ds} = print_drive
($vmid, $drive);
6084 PVE
::QemuConfig-
>write_config($vmid, $conf);
6088 sub qemu_img_convert
{
6089 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6091 my $storecfg = PVE
::Storage
::config
();
6092 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6093 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6095 if ($src_storeid && $dst_storeid) {
6097 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6099 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6100 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6102 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6103 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6105 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6106 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6109 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6110 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6111 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6112 if ($is_zero_initialized) {
6113 push @$cmd, "zeroinit:$dst_path";
6115 push @$cmd, $dst_path;
6120 if($line =~ m/\((\S+)\/100\
%\)/){
6122 my $transferred = int($size * $percent / 100);
6123 my $remaining = $size - $transferred;
6125 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6130 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6132 die "copy failed: $err" if $err;
6136 sub qemu_img_format
{
6137 my ($scfg, $volname) = @_;
6139 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6146 sub qemu_drive_mirror
{
6147 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6149 $jobs = {} if !$jobs;
6153 $jobs->{"drive-$drive"} = {};
6155 if ($dst_volid =~ /^nbd:/) {
6156 $qemu_target = $dst_volid;
6159 my $storecfg = PVE
::Storage
::config
();
6160 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6162 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6164 $format = qemu_img_format
($dst_scfg, $dst_volname);
6166 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6168 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6171 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6172 $opts->{format
} = $format if $format;
6174 print "drive mirror is starting for drive-$drive\n";
6176 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6179 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6180 die "mirroring error: $err";
6183 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6186 sub qemu_drive_mirror_monitor
{
6187 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6190 my $err_complete = 0;
6193 die "storage migration timed out\n" if $err_complete > 300;
6195 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6197 my $running_mirror_jobs = {};
6198 foreach my $stat (@$stats) {
6199 next if $stat->{type
} ne 'mirror';
6200 $running_mirror_jobs->{$stat->{device
}} = $stat;
6203 my $readycounter = 0;
6205 foreach my $job (keys %$jobs) {
6207 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6208 print "$job : finished\n";
6209 delete $jobs->{$job};
6213 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6215 my $busy = $running_mirror_jobs->{$job}->{busy
};
6216 my $ready = $running_mirror_jobs->{$job}->{ready
};
6217 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6218 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6219 my $remaining = $total - $transferred;
6220 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6222 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6225 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6228 last if scalar(keys %$jobs) == 0;
6230 if ($readycounter == scalar(keys %$jobs)) {
6231 print "all mirroring jobs are ready \n";
6232 last if $skipcomplete; #do the complete later
6234 if ($vmiddst && $vmiddst != $vmid) {
6235 my $agent_running = $qga && qga_check_running
($vmid);
6236 if ($agent_running) {
6237 print "freeze filesystem\n";
6238 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6240 print "suspend vm\n";
6241 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6244 # if we clone a disk for a new target vm, we don't switch the disk
6245 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6247 if ($agent_running) {
6248 print "unfreeze filesystem\n";
6249 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6251 print "resume vm\n";
6252 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6258 foreach my $job (keys %$jobs) {
6259 # try to switch the disk if source and destination are on the same guest
6260 print "$job: Completing block job...\n";
6262 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6263 if ($@ =~ m/cannot be completed/) {
6264 print "$job: Block job cannot be completed, try again.\n";
6267 print "$job: Completed successfully.\n";
6268 $jobs->{$job}->{complete
} = 1;
6279 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6280 die "mirroring error: $err";
6285 sub qemu_blockjobs_cancel
{
6286 my ($vmid, $jobs) = @_;
6288 foreach my $job (keys %$jobs) {
6289 print "$job: Cancelling block job\n";
6290 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6291 $jobs->{$job}->{cancel
} = 1;
6295 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6297 my $running_jobs = {};
6298 foreach my $stat (@$stats) {
6299 $running_jobs->{$stat->{device
}} = $stat;
6302 foreach my $job (keys %$jobs) {
6304 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6305 print "$job: Done.\n";
6306 delete $jobs->{$job};
6310 last if scalar(keys %$jobs) == 0;
6317 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6318 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6323 print "create linked clone of drive $drivename ($drive->{file})\n";
6324 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6325 push @$newvollist, $newvolid;
6328 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6329 $storeid = $storage if $storage;
6331 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6332 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6334 print "create full clone of drive $drivename ($drive->{file})\n";
6336 if (drive_is_cloudinit
($drive)) {
6337 $name = "vm-$newvmid-cloudinit";
6338 # cloudinit only supports raw and qcow2 atm:
6339 if ($dst_format eq 'qcow2') {
6341 } elsif ($dst_format ne 'raw') {
6342 die "clone: unhandled format for cloudinit image\n";
6345 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6346 push @$newvollist, $newvolid;
6348 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6350 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6351 if (!$running || $snapname) {
6352 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6355 my $kvmver = get_running_qemu_version
($vmid);
6356 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6357 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6358 if $drive->{iothread
};
6361 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6365 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6368 $disk->{format
} = undef;
6369 $disk->{file
} = $newvolid;
6370 $disk->{size
} = $size;
6375 # this only works if VM is running
6376 sub get_current_qemu_machine
{
6379 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6380 my $res = vm_qmp_command
($vmid, $cmd);
6382 my ($current, $default);
6383 foreach my $e (@$res) {
6384 $default = $e->{name
} if $e->{'is-default'};
6385 $current = $e->{name
} if $e->{'is-current'};
6388 # fallback to the default machine if current is not supported by qemu
6389 return $current || $default || 'pc';
6392 sub get_running_qemu_version
{
6394 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6395 my $res = vm_qmp_command
($vmid, $cmd);
6396 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6399 sub qemu_machine_feature_enabled
{
6400 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6405 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6407 $current_major = $3;
6408 $current_minor = $4;
6410 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6412 $current_major = $1;
6413 $current_minor = $2;
6416 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6421 sub qemu_machine_pxe
{
6422 my ($vmid, $conf, $machine) = @_;
6424 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6426 foreach my $opt (keys %$conf) {
6427 next if $opt !~ m/^net(\d+)$/;
6428 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6430 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6431 return $machine.".pxe" if $romfile =~ m/pxe/;
6438 sub qemu_use_old_bios_files
{
6439 my ($machine_type) = @_;
6441 return if !$machine_type;
6443 my $use_old_bios_files = undef;
6445 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6447 $use_old_bios_files = 1;
6449 my $kvmver = kvm_user_version
();
6450 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6451 # load new efi bios files on migration. So this hack is required to allow
6452 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6453 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6454 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6457 return ($use_old_bios_files, $machine_type);
6460 sub create_efidisk
{
6461 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6463 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6465 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6466 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6467 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6469 my $path = PVE
::Storage
::path
($storecfg, $volid);
6471 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6473 die "Copying EFI vars image failed: $@" if $@;
6475 return ($volid, $vars_size);
6482 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6483 my (undef, $id, $function) = @_;
6484 my $res = { id
=> $id, function
=> $function};
6485 push @{$devices->{$id}}, $res;
6488 # Entries should be sorted by functions.
6489 foreach my $id (keys %$devices) {
6490 my $dev = $devices->{$id};
6491 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6497 sub vm_iothreads_list
{
6500 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6503 foreach my $iothread (@$res) {
6504 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6511 my ($conf, $drive) = @_;
6515 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6517 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6523 my $controller = int($drive->{index} / $maxdev);
6524 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6526 return ($maxdev, $controller, $controller_prefix);
6529 sub add_hyperv_enlightenments
{
6530 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6532 return if $winversion < 6;
6533 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6535 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6537 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6538 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6539 push @$cpuFlags , 'hv_vapic';
6540 push @$cpuFlags , 'hv_time';
6542 push @$cpuFlags , 'hv_spinlocks=0xffff';
6545 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6546 push @$cpuFlags , 'hv_reset';
6547 push @$cpuFlags , 'hv_vpindex';
6548 push @$cpuFlags , 'hv_runtime';
6551 if ($winversion >= 7) {
6552 push @$cpuFlags , 'hv_relaxed';
6556 sub windows_version
{
6559 return 0 if !$ostype;
6563 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6565 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6567 } elsif ($ostype =~ m/^win(\d+)$/) {
6574 sub resolve_dst_disk_format
{
6575 my ($storecfg, $storeid, $src_volname, $format) = @_;
6576 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6579 # if no target format is specified, use the source disk format as hint
6581 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6582 $format = qemu_img_format
($scfg, $src_volname);
6588 # test if requested format is supported - else use default
6589 my $supported = grep { $_ eq $format } @$validFormats;
6590 $format = $defFormat if !$supported;
6594 sub resolve_first_disk
{
6596 my @disks = PVE
::QemuServer
::valid_drive_names
();
6598 foreach my $ds (reverse @disks) {
6599 next if !$conf->{$ds};
6600 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6601 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6607 sub generate_smbios1_uuid
{
6608 my ($uuid, $uuid_str);
6609 UUID
::generate
($uuid);
6610 UUID
::unparse
($uuid, $uuid_str);
6611 return "uuid=$uuid_str";
6614 # bash completion helper
6616 sub complete_backup_archives
{
6617 my ($cmdname, $pname, $cvalue) = @_;
6619 my $cfg = PVE
::Storage
::config
();
6623 if ($cvalue =~ m/^([^:]+):/) {
6627 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6630 foreach my $id (keys %$data) {
6631 foreach my $item (@{$data->{$id}}) {
6632 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6633 push @$res, $item->{volid
} if defined($item->{volid
});
6640 my $complete_vmid_full = sub {
6643 my $idlist = vmstatus
();
6647 foreach my $id (keys %$idlist) {
6648 my $d = $idlist->{$id};
6649 if (defined($running)) {
6650 next if $d->{template
};
6651 next if $running && $d->{status
} ne 'running';
6652 next if !$running && $d->{status
} eq 'running';
6661 return &$complete_vmid_full();
6664 sub complete_vmid_stopped
{
6665 return &$complete_vmid_full(0);
6668 sub complete_vmid_running
{
6669 return &$complete_vmid_full(1);
6672 sub complete_storage
{
6674 my $cfg = PVE
::Storage
::config
();
6675 my $ids = $cfg->{ids
};
6678 foreach my $sid (keys %$ids) {
6679 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6680 next if !$ids->{$sid}->{content
}->{images
};