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.',
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. '
558 . 'Also note that older cloud-init versions do not support hashed passwords.',
563 description
=> "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
567 type
=> 'string', format
=> 'address-list',
568 description
=> "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
573 format
=> 'urlencoded',
574 description
=> "cloud-init : Setup public SSH keys (one key per line, " .
579 # what about other qemu settings ?
581 #machine => 'string',
594 ##soundhw => 'string',
596 while (my ($k, $v) = each %$confdesc) {
597 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
600 my $MAX_IDE_DISKS = 4;
601 my $MAX_SCSI_DISKS = 14;
602 my $MAX_VIRTIO_DISKS = 16;
603 my $MAX_SATA_DISKS = 6;
604 my $MAX_USB_DEVICES = 5;
606 my $MAX_UNUSED_DISKS = 8;
607 my $MAX_HOSTPCI_DEVICES = 4;
608 my $MAX_SERIAL_PORTS = 4;
609 my $MAX_PARALLEL_PORTS = 3;
615 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
616 description
=> "CPUs accessing this NUMA node.",
617 format_description
=> "id[-id];...",
621 description
=> "Amount of memory this NUMA node provides.",
626 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
627 description
=> "Host NUMA nodes to use.",
628 format_description
=> "id[-id];...",
633 enum
=> [qw(preferred bind interleave)],
634 description
=> "NUMA allocation policy.",
638 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
641 type
=> 'string', format
=> $numa_fmt,
642 description
=> "NUMA topology.",
644 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
646 for (my $i = 0; $i < $MAX_NUMA; $i++) {
647 $confdesc->{"numa$i"} = $numadesc;
650 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
651 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
652 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
653 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
655 my $net_fmt_bridge_descr = <<__EOD__;
656 Bridge to attach the network device to. The Proxmox VE standard bridge
659 If you do not specify a bridge, we create a kvm user (NATed) network
660 device, which provides DHCP and DNS services. The following addresses
667 The DHCP server assign addresses to the guest starting from 10.0.2.15.
673 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
674 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
675 format_description
=> "XX:XX:XX:XX:XX:XX",
680 description
=> "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
681 enum
=> $nic_model_list,
684 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
687 description
=> $net_fmt_bridge_descr,
688 format_description
=> 'bridge',
693 minimum
=> 0, maximum
=> 16,
694 description
=> 'Number of packet queues to be used on the device.',
700 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
705 minimum
=> 1, maximum
=> 4094,
706 description
=> 'VLAN tag to apply to packets on this interface.',
711 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
712 description
=> 'VLAN trunks to pass through this interface.',
713 format_description
=> 'vlanid[;vlanid...]',
718 description
=> 'Whether this interface should be protected by the firewall.',
723 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
730 type
=> 'string', format
=> $net_fmt,
731 description
=> "Specify network devices.",
734 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
739 format
=> 'pve-ipv4-config',
740 format_description
=> 'IPv4Format/CIDR',
741 description
=> 'IPv4 address in CIDR format.',
748 format_description
=> 'GatewayIPv4',
749 description
=> 'Default gateway for IPv4 traffic.',
755 format
=> 'pve-ipv6-config',
756 format_description
=> 'IPv6Format/CIDR',
757 description
=> 'IPv6 address in CIDR format.',
764 format_description
=> 'GatewayIPv6',
765 description
=> 'Default gateway for IPv6 traffic.',
770 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
773 type
=> 'string', format
=> 'pve-qm-ipconfig',
774 description
=> <<'EODESCR',
775 cloud-init: Specify IP addresses and gateways for the corresponding interface.
777 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
779 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
780 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
782 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
785 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
787 for (my $i = 0; $i < $MAX_NETS; $i++) {
788 $confdesc->{"net$i"} = $netdesc;
789 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
792 foreach my $key (keys %$confdesc_cloudinit) {
793 $confdesc->{$key} = $confdesc_cloudinit->{$key};
796 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
797 sub verify_volume_id_or_qm_path
{
798 my ($volid, $noerr) = @_;
800 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
804 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
805 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
807 return undef if $noerr;
815 my %drivedesc_base = (
816 volume
=> { alias
=> 'file' },
819 format
=> 'pve-volume-id-or-qm-path',
821 format_description
=> 'volume',
822 description
=> "The drive's backing volume.",
826 enum
=> [qw(cdrom disk)],
827 description
=> "The drive's media type.",
833 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
838 description
=> "Force the drive's physical geometry to have a specific head count.",
843 description
=> "Force the drive's physical geometry to have a specific sector count.",
848 enum
=> [qw(none lba auto)],
849 description
=> "Force disk geometry bios translation mode.",
854 description
=> "Controls qemu's snapshot mode feature."
855 . " If activated, changes made to the disk are temporary and will"
856 . " be discarded when the VM is shutdown.",
861 enum
=> [qw(none writethrough writeback unsafe directsync)],
862 description
=> "The drive's cache mode",
865 format
=> get_standard_option
('pve-qm-image-format'),
868 format
=> 'disk-size',
869 format_description
=> 'DiskSize',
870 description
=> "Disk size. This is purely informational and has no effect.",
875 description
=> "Whether the drive should be included when making backups.",
880 description
=> 'Whether the drive should considered for replication jobs.',
886 enum
=> [qw(ignore report stop)],
887 description
=> 'Read error action.',
892 enum
=> [qw(enospc ignore report stop)],
893 description
=> 'Write error action.',
898 enum
=> [qw(native threads)],
899 description
=> 'AIO type to use.',
904 enum
=> [qw(ignore on)],
905 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
910 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
915 format
=> 'urlencoded',
916 format_description
=> 'serial',
917 maxLength
=> 20*3, # *3 since it's %xx url enoded
918 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
923 description
=> 'Mark this locally-managed volume as available on all nodes',
924 verbose_description
=> "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
930 my %iothread_fmt = ( iothread
=> {
932 description
=> "Whether to use iothreads for this drive",
939 format
=> 'urlencoded',
940 format_description
=> 'model',
941 maxLength
=> 40*3, # *3 since it's %xx url enoded
942 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
950 description
=> "Number of queues.",
956 my %scsiblock_fmt = (
959 description
=> "whether to use scsi-block for full passthrough of host block device\n\nWARNING: can lead to I/O errors in combination with low memory or high memory fragmentation on host",
965 my $add_throttle_desc = sub {
966 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
969 format_description
=> $unit,
970 description
=> "Maximum $what in $longunit.",
973 $d->{minimum
} = $minimum if defined($minimum);
974 $drivedesc_base{$key} = $d;
976 # throughput: (leaky bucket)
977 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
978 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
979 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
980 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
981 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
982 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
983 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
984 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
985 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
987 # pools: (pool of IO before throttling starts taking effect)
988 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
989 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
990 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
991 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
992 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
993 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
996 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
997 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
998 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
999 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1000 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1001 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1004 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1005 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1006 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1007 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1013 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1017 type
=> 'string', format
=> $ide_fmt,
1018 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1020 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1030 type
=> 'string', format
=> $scsi_fmt,
1031 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1033 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1040 type
=> 'string', format
=> $sata_fmt,
1041 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1043 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1051 type
=> 'string', format
=> $virtio_fmt,
1052 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1054 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1056 my $alldrive_fmt = {
1065 volume
=> { alias
=> 'file' },
1068 format
=> 'pve-volume-id-or-qm-path',
1070 format_description
=> 'volume',
1071 description
=> "The drive's backing volume.",
1073 format
=> get_standard_option
('pve-qm-image-format'),
1076 format
=> 'disk-size',
1077 format_description
=> 'DiskSize',
1078 description
=> "Disk size. This is purely informational and has no effect.",
1083 my $efidisk_desc = {
1085 type
=> 'string', format
=> $efidisk_fmt,
1086 description
=> "Configure a Disk for storing EFI vars",
1089 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1094 type
=> 'string', format
=> 'pve-qm-usb-device',
1095 format_description
=> 'HOSTUSBDEVICE|spice',
1096 description
=> <<EODESCR,
1097 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1099 'bus-port(.port)*' (decimal numbers) or
1100 'vendor_id:product_id' (hexadeciaml numbers) or
1103 You can use the 'lsusb -t' command to list existing usb devices.
1105 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1107 The value 'spice' can be used to add a usb redirection devices for spice.
1113 description
=> "Specifies whether if given host option is a USB3 device or port (this does currently not work reliably with spice redirection and is then ignored).",
1120 type
=> 'string', format
=> $usb_fmt,
1121 description
=> "Configure an USB device (n is 0 to 4).",
1123 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1125 # NOTE: the match-groups of this regex are used in parse_hostpci
1126 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1131 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1132 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1133 description
=> <<EODESCR,
1134 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1135 of PCI virtual functions of the host. HOSTPCIID syntax is:
1137 'bus:dev.func' (hexadecimal numbers)
1139 You can us the 'lspci' command to list existing PCI devices.
1144 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1150 pattern
=> '[^,;]+',
1151 format_description
=> 'string',
1152 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1157 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1163 description
=> "Enable vfio-vga device support.",
1168 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1172 type
=> 'string', format
=> 'pve-qm-hostpci',
1173 description
=> "Map host PCI devices into guest.",
1174 verbose_description
=> <<EODESCR,
1175 Map host PCI devices into guest.
1177 NOTE: This option allows direct access to host hardware. So it is no longer
1178 possible to migrate such machines - use with special care.
1180 CAUTION: Experimental! User reported problems with this option.
1183 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1188 pattern
=> '(/dev/.+|socket)',
1189 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1190 verbose_description
=> <<EODESCR,
1191 Create a serial device inside the VM (n is 0 to 3), and pass through a
1192 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1193 host side (use 'qm terminal' to open a terminal connection).
1195 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1197 CAUTION: Experimental! User reported problems with this option.
1204 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1205 description
=> "Map host parallel devices (n is 0 to 2).",
1206 verbose_description
=> <<EODESCR,
1207 Map host parallel devices (n is 0 to 2).
1209 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1211 CAUTION: Experimental! User reported problems with this option.
1215 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1216 $confdesc->{"parallel$i"} = $paralleldesc;
1219 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1220 $confdesc->{"serial$i"} = $serialdesc;
1223 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1224 $confdesc->{"hostpci$i"} = $hostpcidesc;
1227 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1228 $drivename_hash->{"ide$i"} = 1;
1229 $confdesc->{"ide$i"} = $idedesc;
1232 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1233 $drivename_hash->{"sata$i"} = 1;
1234 $confdesc->{"sata$i"} = $satadesc;
1237 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1238 $drivename_hash->{"scsi$i"} = 1;
1239 $confdesc->{"scsi$i"} = $scsidesc ;
1242 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1243 $drivename_hash->{"virtio$i"} = 1;
1244 $confdesc->{"virtio$i"} = $virtiodesc;
1247 $drivename_hash->{efidisk0
} = 1;
1248 $confdesc->{efidisk0
} = $efidisk_desc;
1250 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1251 $confdesc->{"usb$i"} = $usbdesc;
1256 type
=> 'string', format
=> 'pve-volume-id',
1257 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1260 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1261 $confdesc->{"unused$i"} = $unuseddesc;
1264 my $kvm_api_version = 0;
1268 return $kvm_api_version if $kvm_api_version;
1270 my $fh = IO
::File-
>new("</dev/kvm") ||
1273 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1274 $kvm_api_version = $v;
1279 return $kvm_api_version;
1282 my $kvm_user_version;
1284 sub kvm_user_version
{
1286 return $kvm_user_version if $kvm_user_version;
1288 $kvm_user_version = 'unknown';
1292 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1293 $kvm_user_version = $2;
1297 eval { run_command
("kvm -version", outfunc
=> $code); };
1300 return $kvm_user_version;
1304 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1306 sub valid_drive_names
{
1307 # order is important - used to autoselect boot disk
1308 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1309 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1310 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1311 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1315 sub is_valid_drivename
{
1318 return defined($drivename_hash->{$dev});
1323 return defined($confdesc->{$key});
1327 return $nic_model_list;
1330 sub os_list_description
{
1334 wxp
=> 'Windows XP',
1335 w2k
=> 'Windows 2000',
1336 w2k3
=>, 'Windows 2003',
1337 w2k8
=> 'Windows 2008',
1338 wvista
=> 'Windows Vista',
1339 win7
=> 'Windows 7',
1340 win8
=> 'Windows 8/2012',
1341 win10
=> 'Windows 10/2016',
1349 sub get_cdrom_path
{
1351 return $cdrom_path if $cdrom_path;
1353 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1354 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1355 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1359 my ($storecfg, $vmid, $cdrom) = @_;
1361 if ($cdrom eq 'cdrom') {
1362 return get_cdrom_path
();
1363 } elsif ($cdrom eq 'none') {
1365 } elsif ($cdrom =~ m
|^/|) {
1368 return PVE
::Storage
::path
($storecfg, $cdrom);
1372 # try to convert old style file names to volume IDs
1373 sub filename_to_volume_id
{
1374 my ($vmid, $file, $media) = @_;
1376 if (!($file eq 'none' || $file eq 'cdrom' ||
1377 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1379 return undef if $file =~ m
|/|;
1381 if ($media && $media eq 'cdrom') {
1382 $file = "local:iso/$file";
1384 $file = "local:$vmid/$file";
1391 sub verify_media_type
{
1392 my ($opt, $vtype, $media) = @_;
1397 if ($media eq 'disk') {
1399 } elsif ($media eq 'cdrom') {
1402 die "internal error";
1405 return if ($vtype eq $etype);
1407 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1410 sub cleanup_drive_path
{
1411 my ($opt, $storecfg, $drive) = @_;
1413 # try to convert filesystem paths to volume IDs
1415 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1416 ($drive->{file
} !~ m
|^/dev/.+|) &&
1417 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1418 ($drive->{file
} !~ m/^\d+$/)) {
1419 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1420 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1421 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1422 verify_media_type
($opt, $vtype, $drive->{media
});
1423 $drive->{file
} = $volid;
1426 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1429 sub parse_hotplug_features
{
1434 return $res if $data eq '0';
1436 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1438 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1439 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1442 die "invalid hotplug feature '$feature'\n";
1448 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1449 sub pve_verify_hotplug_features
{
1450 my ($value, $noerr) = @_;
1452 return $value if parse_hotplug_features
($value);
1454 return undef if $noerr;
1456 die "unable to parse hotplug option\n";
1459 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1460 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1461 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1462 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1463 # [,iothread=on][,serial=serial][,model=model]
1466 my ($key, $data) = @_;
1468 my ($interface, $index);
1470 if ($key =~ m/^([^\d]+)(\d+)$/) {
1477 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1478 : $confdesc->{$key}->{format
};
1480 warn "invalid drive key: $key\n";
1483 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1484 return undef if !$res;
1485 $res->{interface
} = $interface;
1486 $res->{index} = $index;
1489 foreach my $opt (qw(bps bps_rd bps_wr)) {
1490 if (my $bps = defined(delete $res->{$opt})) {
1491 if (defined($res->{"m$opt"})) {
1492 warn "both $opt and m$opt specified\n";
1496 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1500 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1501 for my $requirement (
1502 [mbps_max
=> 'mbps'],
1503 [mbps_rd_max
=> 'mbps_rd'],
1504 [mbps_wr_max
=> 'mbps_wr'],
1505 [miops_max
=> 'miops'],
1506 [miops_rd_max
=> 'miops_rd'],
1507 [miops_wr_max
=> 'miops_wr'],
1508 [bps_max_length
=> 'mbps_max'],
1509 [bps_rd_max_length
=> 'mbps_rd_max'],
1510 [bps_wr_max_length
=> 'mbps_wr_max'],
1511 [iops_max_length
=> 'iops_max'],
1512 [iops_rd_max_length
=> 'iops_rd_max'],
1513 [iops_wr_max_length
=> 'iops_wr_max']) {
1514 my ($option, $requires) = @$requirement;
1515 if ($res->{$option} && !$res->{$requires}) {
1516 warn "$option requires $requires\n";
1521 return undef if $error;
1523 return undef if $res->{mbps_rd
} && $res->{mbps
};
1524 return undef if $res->{mbps_wr
} && $res->{mbps
};
1525 return undef if $res->{iops_rd
} && $res->{iops
};
1526 return undef if $res->{iops_wr
} && $res->{iops
};
1528 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1529 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1530 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1531 return undef if $res->{interface
} eq 'virtio';
1534 if (my $size = $res->{size
}) {
1535 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1542 my ($vmid, $drive) = @_;
1543 my $data = { %$drive };
1544 delete $data->{$_} for qw(index interface);
1545 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1549 my($fh, $noerr) = @_;
1552 my $SG_GET_VERSION_NUM = 0x2282;
1554 my $versionbuf = "\x00" x
8;
1555 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1557 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1560 my $version = unpack("I", $versionbuf);
1561 if ($version < 30000) {
1562 die "scsi generic interface too old\n" if !$noerr;
1566 my $buf = "\x00" x
36;
1567 my $sensebuf = "\x00" x
8;
1568 my $cmd = pack("C x3 C x1", 0x12, 36);
1570 # see /usr/include/scsi/sg.h
1571 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1573 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1574 length($sensebuf), 0, length($buf), $buf,
1575 $cmd, $sensebuf, 6000);
1577 $ret = ioctl($fh, $SG_IO, $packet);
1579 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1583 my @res = unpack($sg_io_hdr_t, $packet);
1584 if ($res[17] || $res[18]) {
1585 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1590 (my $byte0, my $byte1, $res->{vendor
},
1591 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1593 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1594 $res->{type
} = $byte0 & 31;
1602 my $fh = IO
::File-
>new("+<$path") || return undef;
1603 my $res = scsi_inquiry
($fh, 1);
1609 sub machine_type_is_q35
{
1612 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1615 sub print_tabletdevice_full
{
1618 my $q35 = machine_type_is_q35
($conf);
1620 # we use uhci for old VMs because tablet driver was buggy in older qemu
1621 my $usbbus = $q35 ?
"ehci" : "uhci";
1623 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1626 sub print_drivedevice_full
{
1627 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1632 if ($drive->{interface
} eq 'virtio') {
1633 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1634 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1635 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1636 } elsif ($drive->{interface
} eq 'scsi') {
1638 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1639 my $unit = $drive->{index} % $maxdev;
1640 my $devicetype = 'hd';
1642 if (drive_is_cdrom
($drive)) {
1645 if ($drive->{file
} =~ m
|^/|) {
1646 $path = $drive->{file
};
1647 if (my $info = path_is_scsi
($path)) {
1648 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1649 $devicetype = 'block';
1650 } elsif ($info->{type
} == 1) { # tape
1651 $devicetype = 'generic';
1655 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1658 if($path =~ m/^iscsi\:\/\
//){
1659 $devicetype = 'generic';
1663 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1664 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1666 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0,lun=$drive->{index},drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1669 } elsif ($drive->{interface
} eq 'ide'){
1671 my $controller = int($drive->{index} / $maxdev);
1672 my $unit = $drive->{index} % $maxdev;
1673 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1675 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1676 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1677 $model = URI
::Escape
::uri_unescape
($model);
1678 $device .= ",model=$model";
1680 } elsif ($drive->{interface
} eq 'sata'){
1681 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1682 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1683 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1684 } elsif ($drive->{interface
} eq 'usb') {
1686 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1688 die "unsupported interface type";
1691 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1696 sub get_initiator_name
{
1699 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1700 while (defined(my $line = <$fh>)) {
1701 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1710 sub print_drive_full
{
1711 my ($storecfg, $vmid, $drive) = @_;
1714 my $volid = $drive->{file
};
1717 if (drive_is_cdrom
($drive)) {
1718 $path = get_iso_path
($storecfg, $vmid, $volid);
1720 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1722 $path = PVE
::Storage
::path
($storecfg, $volid);
1723 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1724 $format = qemu_img_format
($scfg, $volname);
1732 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1733 foreach my $o (@qemu_drive_options) {
1734 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1737 # snapshot only accepts on|off
1738 if (defined($drive->{snapshot
})) {
1739 my $v = $drive->{snapshot
} ?
'on' : 'off';
1740 $opts .= ",snapshot=$v";
1743 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1744 my ($dir, $qmpname) = @$type;
1745 if (my $v = $drive->{"mbps$dir"}) {
1746 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1748 if (my $v = $drive->{"mbps${dir}_max"}) {
1749 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1751 if (my $v = $drive->{"bps${dir}_max_length"}) {
1752 $opts .= ",throttling.bps$qmpname-max-length=$v";
1754 if (my $v = $drive->{"iops${dir}"}) {
1755 $opts .= ",throttling.iops$qmpname=$v";
1757 if (my $v = $drive->{"iops${dir}_max"}) {
1758 $opts .= ",throttling.iops$qmpname-max=$v";
1760 if (my $v = $drive->{"iops${dir}_max_length"}) {
1761 $opts .= ",throttling.iops$qmpname-max-length=$v";
1765 if (my $serial = $drive->{serial
}) {
1766 $serial = URI
::Escape
::uri_unescape
($serial);
1767 $opts .= ",serial=$serial";
1770 $opts .= ",format=$format" if $format && !$drive->{format
};
1772 my $cache_direct = 0;
1774 if (my $cache = $drive->{cache
}) {
1775 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1776 } elsif (!drive_is_cdrom
($drive)) {
1777 $opts .= ",cache=none";
1781 # aio native works only with O_DIRECT
1782 if (!$drive->{aio
}) {
1784 $opts .= ",aio=native";
1786 $opts .= ",aio=threads";
1790 if (!drive_is_cdrom
($drive)) {
1792 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1793 $detectzeroes = 'off';
1794 } elsif ($drive->{discard
}) {
1795 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1797 # This used to be our default with discard not being specified:
1798 $detectzeroes = 'on';
1800 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1803 my $pathinfo = $path ?
"file=$path," : '';
1805 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1808 sub print_netdevice_full
{
1809 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1811 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1813 my $device = $net->{model
};
1814 if ($net->{model
} eq 'virtio') {
1815 $device = 'virtio-net-pci';
1818 my $pciaddr = print_pci_addr
("$netid", $bridges);
1819 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1820 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1821 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1822 my $vectors = $net->{queues
} * 2 + 2;
1823 $tmpstr .= ",vectors=$vectors,mq=on";
1825 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1827 if ($use_old_bios_files) {
1829 if ($device eq 'virtio-net-pci') {
1830 $romfile = 'pxe-virtio.rom';
1831 } elsif ($device eq 'e1000') {
1832 $romfile = 'pxe-e1000.rom';
1833 } elsif ($device eq 'ne2k') {
1834 $romfile = 'pxe-ne2k_pci.rom';
1835 } elsif ($device eq 'pcnet') {
1836 $romfile = 'pxe-pcnet.rom';
1837 } elsif ($device eq 'rtl8139') {
1838 $romfile = 'pxe-rtl8139.rom';
1840 $tmpstr .= ",romfile=$romfile" if $romfile;
1846 sub print_netdev_full
{
1847 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1850 if ($netid =~ m/^net(\d+)$/) {
1854 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1856 my $ifname = "tap${vmid}i$i";
1858 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1859 die "interface name '$ifname' is too long (max 15 character)\n"
1860 if length($ifname) >= 16;
1862 my $vhostparam = '';
1863 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1865 my $vmname = $conf->{name
} || "vm$vmid";
1868 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1870 if ($net->{bridge
}) {
1871 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1873 $netdev = "type=user,id=$netid,hostname=$vmname";
1876 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1882 sub print_cpu_device
{
1883 my ($conf, $id) = @_;
1885 my $kvm = $conf->{kvm
} // 1;
1886 my $cpu = $kvm ?
"kvm64" : "qemu64";
1887 if (my $cputype = $conf->{cpu
}) {
1888 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1889 or die "Cannot parse cpu description: $cputype\n";
1890 $cpu = $cpuconf->{cputype
};
1893 my $cores = $conf->{cores
} || 1;
1895 my $current_core = ($id - 1) % $cores;
1896 my $current_socket = int(($id - 1 - $current_core)/$cores);
1898 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1901 sub drive_is_cloudinit
{
1903 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1906 sub drive_is_cdrom
{
1907 my ($drive, $exclude_cloudinit) = @_;
1909 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1911 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1915 sub parse_number_sets
{
1918 foreach my $part (split(/;/, $set)) {
1919 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1920 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1921 push @$res, [ $1, $2 ];
1923 die "invalid range: $part\n";
1932 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1933 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1934 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1941 return undef if !$value;
1943 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1945 my @idlist = split(/;/, $res->{host
});
1946 delete $res->{host
};
1947 foreach my $id (@idlist) {
1948 if ($id =~ /^$PCIRE$/) {
1950 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1952 my $pcidevices = lspci
($1);
1953 $res->{pciid
} = $pcidevices->{$1};
1956 # should have been caught by parse_property_string already
1957 die "failed to parse PCI id: $id\n";
1963 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1967 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1972 if (!defined($res->{macaddr
})) {
1973 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1974 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1976 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
() if !defined($res->{macaddr
});
1980 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1981 sub parse_ipconfig
{
1984 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1990 if ($res->{gw
} && !$res->{ip
}) {
1991 warn 'gateway specified without specifying an IP address';
1994 if ($res->{gw6
} && !$res->{ip6
}) {
1995 warn 'IPv6 gateway specified without specifying an IPv6 address';
1998 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1999 warn 'gateway specified together with DHCP';
2002 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2004 warn "IPv6 gateway specified together with $res->{ip6} address";
2008 if (!$res->{ip
} && !$res->{ip6
}) {
2009 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2018 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2021 sub add_random_macs
{
2022 my ($settings) = @_;
2024 foreach my $opt (keys %$settings) {
2025 next if $opt !~ m/^net(\d+)$/;
2026 my $net = parse_net
($settings->{$opt});
2028 $settings->{$opt} = print_net
($net);
2032 sub vm_is_volid_owner
{
2033 my ($storecfg, $vmid, $volid) = @_;
2035 if ($volid !~ m
|^/|) {
2037 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2038 if ($owner && ($owner == $vmid)) {
2046 sub split_flagged_list
{
2047 my $text = shift || '';
2048 $text =~ s/[,;]/ /g;
2050 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2053 sub join_flagged_list
{
2054 my ($how, $lst) = @_;
2055 join $how, map { $lst->{$_} . $_ } keys %$lst;
2058 sub vmconfig_delete_pending_option
{
2059 my ($conf, $key, $force) = @_;
2061 delete $conf->{pending
}->{$key};
2062 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2063 $pending_delete_hash->{$key} = $force ?
'!' : '';
2064 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2067 sub vmconfig_undelete_pending_option
{
2068 my ($conf, $key) = @_;
2070 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2071 delete $pending_delete_hash->{$key};
2073 if (%$pending_delete_hash) {
2074 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2076 delete $conf->{pending
}->{delete};
2080 sub vmconfig_register_unused_drive
{
2081 my ($storecfg, $vmid, $conf, $drive) = @_;
2083 if (drive_is_cloudinit
($drive)) {
2084 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2086 } elsif (!drive_is_cdrom
($drive)) {
2087 my $volid = $drive->{file
};
2088 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2089 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2094 sub vmconfig_cleanup_pending
{
2097 # remove pending changes when nothing changed
2099 foreach my $opt (keys %{$conf->{pending
}}) {
2100 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2102 delete $conf->{pending
}->{$opt};
2106 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2107 my $pending_delete_hash = {};
2108 while (my ($opt, $force) = each %$current_delete_hash) {
2109 if (defined($conf->{$opt})) {
2110 $pending_delete_hash->{$opt} = $force;
2116 if (%$pending_delete_hash) {
2117 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2119 delete $conf->{pending
}->{delete};
2125 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2129 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2130 format_description
=> 'UUID',
2131 description
=> "Set SMBIOS1 UUID.",
2137 format_description
=> 'string',
2138 description
=> "Set SMBIOS1 version.",
2144 format_description
=> 'string',
2145 description
=> "Set SMBIOS1 serial number.",
2151 format_description
=> 'string',
2152 description
=> "Set SMBIOS1 manufacturer.",
2158 format_description
=> 'string',
2159 description
=> "Set SMBIOS1 product ID.",
2165 format_description
=> 'string',
2166 description
=> "Set SMBIOS1 SKU string.",
2172 format_description
=> 'string',
2173 description
=> "Set SMBIOS1 family string.",
2181 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2188 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2191 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2193 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2194 sub verify_bootdisk
{
2195 my ($value, $noerr) = @_;
2197 return $value if is_valid_drivename
($value);
2199 return undef if $noerr;
2201 die "invalid boot disk '$value'\n";
2204 sub parse_watchdog
{
2207 return undef if !$value;
2209 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2214 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2215 sub verify_usb_device
{
2216 my ($value, $noerr) = @_;
2218 return $value if parse_usb_device
($value);
2220 return undef if $noerr;
2222 die "unable to parse usb device\n";
2225 # add JSON properties for create and set function
2226 sub json_config_properties
{
2229 foreach my $opt (keys %$confdesc) {
2230 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2231 $prop->{$opt} = $confdesc->{$opt};
2238 my ($key, $value) = @_;
2240 die "unknown setting '$key'\n" if !$confdesc->{$key};
2242 my $type = $confdesc->{$key}->{type
};
2244 if (!defined($value)) {
2245 die "got undefined value\n";
2248 if ($value =~ m/[\n\r]/) {
2249 die "property contains a line feed\n";
2252 if ($type eq 'boolean') {
2253 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2254 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2255 die "type check ('boolean') failed - got '$value'\n";
2256 } elsif ($type eq 'integer') {
2257 return int($1) if $value =~ m/^(\d+)$/;
2258 die "type check ('integer') failed - got '$value'\n";
2259 } elsif ($type eq 'number') {
2260 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2261 die "type check ('number') failed - got '$value'\n";
2262 } elsif ($type eq 'string') {
2263 if (my $fmt = $confdesc->{$key}->{format
}) {
2264 PVE
::JSONSchema
::check_format
($fmt, $value);
2267 $value =~ s/^\"(.*)\"$/$1/;
2270 die "internal error"
2274 sub check_iommu_support
{
2275 #fixme : need to check IOMMU support
2276 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2286 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2287 utime undef, undef, $conf;
2291 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2293 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2295 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2297 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2299 if ($conf->{template
}) {
2300 # check if any base image is still used by a linked clone
2301 foreach_drive
($conf, sub {
2302 my ($ds, $drive) = @_;
2304 return if drive_is_cdrom
($drive);
2306 my $volid = $drive->{file
};
2308 return if !$volid || $volid =~ m
|^/|;
2310 die "base volume '$volid' is still in use by linked cloned\n"
2311 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2316 # only remove disks owned by this VM
2317 foreach_drive
($conf, sub {
2318 my ($ds, $drive) = @_;
2320 return if drive_is_cdrom
($drive, 1);
2322 my $volid = $drive->{file
};
2324 return if !$volid || $volid =~ m
|^/|;
2326 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2327 return if !$path || !$owner || ($owner != $vmid);
2330 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2332 warn "Could not remove disk '$volid', check manually: $@" if $@;
2336 if ($keep_empty_config) {
2337 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2342 # also remove unused disk
2344 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2347 PVE
::Storage
::foreach_volid
($dl, sub {
2348 my ($volid, $sid, $volname, $d) = @_;
2349 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2358 sub parse_vm_config
{
2359 my ($filename, $raw) = @_;
2361 return undef if !defined($raw);
2364 digest
=> Digest
::SHA
::sha1_hex
($raw),
2369 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2370 || die "got strange filename '$filename'";
2378 my @lines = split(/\n/, $raw);
2379 foreach my $line (@lines) {
2380 next if $line =~ m/^\s*$/;
2382 if ($line =~ m/^\[PENDING\]\s*$/i) {
2383 $section = 'pending';
2384 if (defined($descr)) {
2386 $conf->{description
} = $descr;
2389 $conf = $res->{$section} = {};
2392 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2394 if (defined($descr)) {
2396 $conf->{description
} = $descr;
2399 $conf = $res->{snapshots
}->{$section} = {};
2403 if ($line =~ m/^\#(.*)\s*$/) {
2404 $descr = '' if !defined($descr);
2405 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2409 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2410 $descr = '' if !defined($descr);
2411 $descr .= PVE
::Tools
::decode_text
($2);
2412 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2413 $conf->{snapstate
} = $1;
2414 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2417 $conf->{$key} = $value;
2418 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2420 if ($section eq 'pending') {
2421 $conf->{delete} = $value; # we parse this later
2423 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2425 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2428 eval { $value = check_type
($key, $value); };
2430 warn "vm $vmid - unable to parse value of '$key' - $@";
2432 $key = 'ide2' if $key eq 'cdrom';
2433 my $fmt = $confdesc->{$key}->{format
};
2434 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2435 my $v = parse_drive
($key, $value);
2436 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2437 $v->{file
} = $volid;
2438 $value = print_drive
($vmid, $v);
2440 warn "vm $vmid - unable to parse value of '$key'\n";
2445 $conf->{$key} = $value;
2450 if (defined($descr)) {
2452 $conf->{description
} = $descr;
2454 delete $res->{snapstate
}; # just to be sure
2459 sub write_vm_config
{
2460 my ($filename, $conf) = @_;
2462 delete $conf->{snapstate
}; # just to be sure
2464 if ($conf->{cdrom
}) {
2465 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2466 $conf->{ide2
} = $conf->{cdrom
};
2467 delete $conf->{cdrom
};
2470 # we do not use 'smp' any longer
2471 if ($conf->{sockets
}) {
2472 delete $conf->{smp
};
2473 } elsif ($conf->{smp
}) {
2474 $conf->{sockets
} = $conf->{smp
};
2475 delete $conf->{cores
};
2476 delete $conf->{smp
};
2479 my $used_volids = {};
2481 my $cleanup_config = sub {
2482 my ($cref, $pending, $snapname) = @_;
2484 foreach my $key (keys %$cref) {
2485 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2486 $key eq 'snapstate' || $key eq 'pending';
2487 my $value = $cref->{$key};
2488 if ($key eq 'delete') {
2489 die "propertry 'delete' is only allowed in [PENDING]\n"
2491 # fixme: check syntax?
2494 eval { $value = check_type
($key, $value); };
2495 die "unable to parse value of '$key' - $@" if $@;
2497 $cref->{$key} = $value;
2499 if (!$snapname && is_valid_drivename
($key)) {
2500 my $drive = parse_drive
($key, $value);
2501 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2506 &$cleanup_config($conf);
2508 &$cleanup_config($conf->{pending
}, 1);
2510 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2511 die "internal error" if $snapname eq 'pending';
2512 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2515 # remove 'unusedX' settings if we re-add a volume
2516 foreach my $key (keys %$conf) {
2517 my $value = $conf->{$key};
2518 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2519 delete $conf->{$key};
2523 my $generate_raw_config = sub {
2524 my ($conf, $pending) = @_;
2528 # add description as comment to top of file
2529 if (defined(my $descr = $conf->{description
})) {
2531 foreach my $cl (split(/\n/, $descr)) {
2532 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2535 $raw .= "#\n" if $pending;
2539 foreach my $key (sort keys %$conf) {
2540 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2541 $raw .= "$key: $conf->{$key}\n";
2546 my $raw = &$generate_raw_config($conf);
2548 if (scalar(keys %{$conf->{pending
}})){
2549 $raw .= "\n[PENDING]\n";
2550 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2553 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2554 $raw .= "\n[$snapname]\n";
2555 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2565 # we use static defaults from our JSON schema configuration
2566 foreach my $key (keys %$confdesc) {
2567 if (defined(my $default = $confdesc->{$key}->{default})) {
2568 $res->{$key} = $default;
2572 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2573 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2579 my $vmlist = PVE
::Cluster
::get_vmlist
();
2581 return $res if !$vmlist || !$vmlist->{ids
};
2582 my $ids = $vmlist->{ids
};
2584 foreach my $vmid (keys %$ids) {
2585 my $d = $ids->{$vmid};
2586 next if !$d->{node
} || $d->{node
} ne $nodename;
2587 next if !$d->{type
} || $d->{type
} ne 'qemu';
2588 $res->{$vmid}->{exists} = 1;
2593 # test if VM uses local resources (to prevent migration)
2594 sub check_local_resources
{
2595 my ($conf, $noerr) = @_;
2599 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2600 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2602 foreach my $k (keys %$conf) {
2603 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2604 # sockets are safe: they will recreated be on the target side post-migrate
2605 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2606 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2609 die "VM uses local resources\n" if $loc_res && !$noerr;
2614 # check if used storages are available on all nodes (use by migrate)
2615 sub check_storage_availability
{
2616 my ($storecfg, $conf, $node) = @_;
2618 foreach_drive
($conf, sub {
2619 my ($ds, $drive) = @_;
2621 my $volid = $drive->{file
};
2624 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2627 # check if storage is available on both nodes
2628 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2629 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2633 # list nodes where all VM images are available (used by has_feature API)
2635 my ($conf, $storecfg) = @_;
2637 my $nodelist = PVE
::Cluster
::get_nodelist
();
2638 my $nodehash = { map { $_ => 1 } @$nodelist };
2639 my $nodename = PVE
::INotify
::nodename
();
2641 foreach_drive
($conf, sub {
2642 my ($ds, $drive) = @_;
2644 my $volid = $drive->{file
};
2647 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2649 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2650 if ($scfg->{disable
}) {
2652 } elsif (my $avail = $scfg->{nodes
}) {
2653 foreach my $node (keys %$nodehash) {
2654 delete $nodehash->{$node} if !$avail->{$node};
2656 } elsif (!$scfg->{shared
}) {
2657 foreach my $node (keys %$nodehash) {
2658 delete $nodehash->{$node} if $node ne $nodename
2668 my ($pidfile, $pid) = @_;
2670 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2674 return undef if !$line;
2675 my @param = split(/\0/, $line);
2677 my $cmd = $param[0];
2678 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2680 for (my $i = 0; $i < scalar (@param); $i++) {
2683 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2684 my $p = $param[$i+1];
2685 return 1 if $p && ($p eq $pidfile);
2694 my ($vmid, $nocheck, $node) = @_;
2696 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2698 die "unable to find configuration file for VM $vmid - no such machine\n"
2699 if !$nocheck && ! -f
$filename;
2701 my $pidfile = pidfile_name
($vmid);
2703 if (my $fd = IO
::File-
>new("<$pidfile")) {
2708 my $mtime = $st->mtime;
2709 if ($mtime > time()) {
2710 warn "file '$filename' modified in future\n";
2713 if ($line =~ m/^(\d+)$/) {
2715 if (check_cmdline
($pidfile, $pid)) {
2716 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2728 my $vzlist = config_list
();
2730 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2732 while (defined(my $de = $fd->read)) {
2733 next if $de !~ m/^(\d+)\.pid$/;
2735 next if !defined($vzlist->{$vmid});
2736 if (my $pid = check_running
($vmid)) {
2737 $vzlist->{$vmid}->{pid
} = $pid;
2745 my ($storecfg, $conf) = @_;
2747 my $bootdisk = $conf->{bootdisk
};
2748 return undef if !$bootdisk;
2749 return undef if !is_valid_drivename
($bootdisk);
2751 return undef if !$conf->{$bootdisk};
2753 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2754 return undef if !defined($drive);
2756 return undef if drive_is_cdrom
($drive);
2758 my $volid = $drive->{file
};
2759 return undef if !$volid;
2761 return $drive->{size
};
2764 my $last_proc_pid_stat;
2766 # get VM status information
2767 # This must be fast and should not block ($full == false)
2768 # We only query KVM using QMP if $full == true (this can be slow)
2770 my ($opt_vmid, $full) = @_;
2774 my $storecfg = PVE
::Storage
::config
();
2776 my $list = vzlist
();
2777 my $defaults = load_defaults
();
2779 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2781 my $cpucount = $cpuinfo->{cpus
} || 1;
2783 foreach my $vmid (keys %$list) {
2784 next if $opt_vmid && ($vmid ne $opt_vmid);
2786 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2787 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2790 $d->{pid
} = $list->{$vmid}->{pid
};
2792 # fixme: better status?
2793 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2795 my $size = disksize
($storecfg, $conf);
2796 if (defined($size)) {
2797 $d->{disk
} = 0; # no info available
2798 $d->{maxdisk
} = $size;
2804 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2805 * ($conf->{cores
} || $defaults->{cores
});
2806 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2807 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2809 $d->{name
} = $conf->{name
} || "VM $vmid";
2810 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2811 : $defaults->{memory
}*(1024*1024);
2813 if ($conf->{balloon
}) {
2814 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2815 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2816 : $defaults->{shares
};
2827 $d->{diskwrite
} = 0;
2829 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2831 $d->{serial
} = 1 if conf_has_serial
($conf);
2836 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2837 foreach my $dev (keys %$netdev) {
2838 next if $dev !~ m/^tap([1-9]\d*)i/;
2840 my $d = $res->{$vmid};
2843 $d->{netout
} += $netdev->{$dev}->{receive
};
2844 $d->{netin
} += $netdev->{$dev}->{transmit
};
2847 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2848 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2853 my $ctime = gettimeofday
;
2855 foreach my $vmid (keys %$list) {
2857 my $d = $res->{$vmid};
2858 my $pid = $d->{pid
};
2861 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2862 next if !$pstat; # not running
2864 my $used = $pstat->{utime} + $pstat->{stime
};
2866 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2868 if ($pstat->{vsize
}) {
2869 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2872 my $old = $last_proc_pid_stat->{$pid};
2874 $last_proc_pid_stat->{$pid} = {
2882 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2884 if ($dtime > 1000) {
2885 my $dutime = $used - $old->{used
};
2887 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2888 $last_proc_pid_stat->{$pid} = {
2894 $d->{cpu
} = $old->{cpu
};
2898 return $res if !$full;
2900 my $qmpclient = PVE
::QMPClient-
>new();
2902 my $ballooncb = sub {
2903 my ($vmid, $resp) = @_;
2905 my $info = $resp->{'return'};
2906 return if !$info->{max_mem
};
2908 my $d = $res->{$vmid};
2910 # use memory assigned to VM
2911 $d->{maxmem
} = $info->{max_mem
};
2912 $d->{balloon
} = $info->{actual
};
2914 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2915 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2916 $d->{freemem
} = $info->{free_mem
};
2919 $d->{ballooninfo
} = $info;
2922 my $blockstatscb = sub {
2923 my ($vmid, $resp) = @_;
2924 my $data = $resp->{'return'} || [];
2925 my $totalrdbytes = 0;
2926 my $totalwrbytes = 0;
2928 for my $blockstat (@$data) {
2929 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2930 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2932 $blockstat->{device
} =~ s/drive-//;
2933 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2935 $res->{$vmid}->{diskread
} = $totalrdbytes;
2936 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2939 my $statuscb = sub {
2940 my ($vmid, $resp) = @_;
2942 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2943 # this fails if ballon driver is not loaded, so this must be
2944 # the last commnand (following command are aborted if this fails).
2945 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2947 my $status = 'unknown';
2948 if (!defined($status = $resp->{'return'}->{status
})) {
2949 warn "unable to get VM status\n";
2953 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2956 foreach my $vmid (keys %$list) {
2957 next if $opt_vmid && ($vmid ne $opt_vmid);
2958 next if !$res->{$vmid}->{pid
}; # not running
2959 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2962 $qmpclient->queue_execute(undef, 2);
2964 foreach my $vmid (keys %$list) {
2965 next if $opt_vmid && ($vmid ne $opt_vmid);
2966 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2973 my ($conf, $func, @param) = @_;
2975 foreach my $ds (valid_drive_names
()) {
2976 next if !defined($conf->{$ds});
2978 my $drive = parse_drive
($ds, $conf->{$ds});
2981 &$func($ds, $drive, @param);
2986 my ($conf, $func, @param) = @_;
2990 my $test_volid = sub {
2991 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
2995 $volhash->{$volid}->{cdrom
} //= 1;
2996 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
2998 $volhash->{$volid}->{replicate
} //= 0;
2999 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3001 $volhash->{$volid}->{shared
} //= 0;
3002 $volhash->{$volid}->{shared
} = 1 if $shared;
3004 $volhash->{$volid}->{referenced_in_config
} //= 0;
3005 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3007 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3008 if defined($snapname);
3011 foreach_drive
($conf, sub {
3012 my ($ds, $drive) = @_;
3013 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3016 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3017 my $snap = $conf->{snapshots
}->{$snapname};
3018 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3019 foreach_drive
($snap, sub {
3020 my ($ds, $drive) = @_;
3021 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3025 foreach my $volid (keys %$volhash) {
3026 &$func($volid, $volhash->{$volid}, @param);
3030 sub conf_has_serial
{
3033 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3034 if ($conf->{"serial$i"}) {
3042 sub vga_conf_has_spice
{
3045 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3050 sub config_to_command
{
3051 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3054 my $globalFlags = [];
3055 my $machineFlags = [];
3061 my $kvmver = kvm_user_version
();
3062 my $vernum = 0; # unknown
3063 my $ostype = $conf->{ostype
};
3064 my $winversion = windows_version
($ostype);
3065 my $kvm = $conf->{kvm
} // 1;
3067 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3069 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3070 $vernum = $1*1000000+$2*1000;
3071 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3072 $vernum = $1*1000000+$2*1000+$3;
3075 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3077 my $have_ovz = -f
'/proc/vz/vestat';
3079 my $q35 = machine_type_is_q35
($conf);
3080 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3081 my $machine_type = $forcemachine || $conf->{machine
};
3082 my $use_old_bios_files = undef;
3083 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3085 my $cpuunits = defined($conf->{cpuunits
}) ?
3086 $conf->{cpuunits
} : $defaults->{cpuunits
};
3088 push @$cmd, '/usr/bin/kvm';
3090 push @$cmd, '-id', $vmid;
3094 my $qmpsocket = qmp_socket
($vmid);
3095 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3096 push @$cmd, '-mon', "chardev=qmp,mode=control";
3099 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3101 push @$cmd, '-daemonize';
3103 if ($conf->{smbios1
}) {
3104 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3107 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3108 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3112 if (my $efidisk = $conf->{efidisk0
}) {
3113 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3114 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3115 $format = $d->{format
};
3117 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3118 if (!defined($format)) {
3119 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3120 $format = qemu_img_format
($scfg, $volname);
3124 die "efidisk format must be specified\n"
3125 if !defined($format);
3128 warn "no efidisk configured! Using temporary efivars disk.\n";
3129 $path = "/tmp/$vmid-ovmf.fd";
3130 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3134 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3135 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3139 # add usb controllers
3140 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3141 push @$devices, @usbcontrollers if @usbcontrollers;
3142 my $vga = $conf->{vga
};
3144 my $qxlnum = vga_conf_has_spice
($vga);
3145 $vga = 'qxl' if $qxlnum;
3148 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3149 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3151 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3155 # enable absolute mouse coordinates (needed by vnc)
3157 if (defined($conf->{tablet
})) {
3158 $tablet = $conf->{tablet
};
3160 $tablet = $defaults->{tablet
};
3161 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3162 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3165 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3168 my $gpu_passthrough;
3171 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3172 my $d = parse_hostpci
($conf->{"hostpci$i"});
3175 my $pcie = $d->{pcie
};
3177 die "q35 machine model is not enabled" if !$q35;
3178 $pciaddr = print_pcie_addr
("hostpci$i");
3180 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3183 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3184 my $romfile = $d->{romfile
};
3187 if ($d->{'x-vga'}) {
3188 $xvga = ',x-vga=on';
3191 $gpu_passthrough = 1;
3193 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3197 my $pcidevices = $d->{pciid
};
3198 my $multifunction = 1 if @$pcidevices > 1;
3201 foreach my $pcidevice (@$pcidevices) {
3203 my $id = "hostpci$i";
3204 $id .= ".$j" if $multifunction;
3205 my $addr = $pciaddr;
3206 $addr .= ".$j" if $multifunction;
3207 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3210 $devicestr .= "$rombar$xvga";
3211 $devicestr .= ",multifunction=on" if $multifunction;
3212 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3215 push @$devices, '-device', $devicestr;
3221 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3222 push @$devices, @usbdevices if @usbdevices;
3224 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3225 if (my $path = $conf->{"serial$i"}) {
3226 if ($path eq 'socket') {
3227 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3228 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3229 push @$devices, '-device', "isa-serial,chardev=serial$i";
3231 die "no such serial device\n" if ! -c
$path;
3232 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3233 push @$devices, '-device', "isa-serial,chardev=serial$i";
3239 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3240 if (my $path = $conf->{"parallel$i"}) {
3241 die "no such parallel device\n" if ! -c
$path;
3242 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3243 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3244 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3248 my $vmname = $conf->{name
} || "vm$vmid";
3250 push @$cmd, '-name', $vmname;
3253 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3254 $sockets = $conf->{sockets
} if $conf->{sockets
};
3256 my $cores = $conf->{cores
} || 1;
3258 my $maxcpus = $sockets * $cores;
3260 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3262 my $allowed_vcpus = $cpuinfo->{cpus
};
3264 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3265 if ($allowed_vcpus < $maxcpus);
3267 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3269 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3270 for (my $i = 2; $i <= $vcpus; $i++) {
3271 my $cpustr = print_cpu_device
($conf,$i);
3272 push @$cmd, '-device', $cpustr;
3277 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3279 push @$cmd, '-nodefaults';
3281 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3283 my $bootindex_hash = {};
3285 foreach my $o (split(//, $bootorder)) {
3286 $bootindex_hash->{$o} = $i*100;
3290 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3292 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3294 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3296 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3298 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3299 my $socket = vnc_socket
($vmid);
3300 push @$cmd, '-vnc', "unix:$socket,x509,password";
3302 push @$cmd, '-nographic';
3306 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3308 my $useLocaltime = $conf->{localtime};
3310 if ($winversion >= 5) { # windows
3311 $useLocaltime = 1 if !defined($conf->{localtime});
3313 # use time drift fix when acpi is enabled
3314 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3315 $tdf = 1 if !defined($conf->{tdf
});
3319 if ($winversion >= 6) {
3320 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3321 push @$cmd, '-no-hpet';
3324 push @$rtcFlags, 'driftfix=slew' if $tdf;
3327 push @$machineFlags, 'accel=tcg';
3330 if ($machine_type) {
3331 push @$machineFlags, "type=${machine_type}";
3334 if ($conf->{startdate
}) {
3335 push @$rtcFlags, "base=$conf->{startdate}";
3336 } elsif ($useLocaltime) {
3337 push @$rtcFlags, 'base=localtime';
3340 my $cpu = $kvm ?
"kvm64" : "qemu64";
3341 if (my $cputype = $conf->{cpu
}) {
3342 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3343 or die "Cannot parse cpu description: $cputype\n";
3344 $cpu = $cpuconf->{cputype
};
3345 $kvm_off = 1 if $cpuconf->{hidden
};
3347 if (defined(my $flags = $cpuconf->{flags
})) {
3348 push @$cpuFlags, split(";", $flags);
3352 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3354 push @$cpuFlags , '-x2apic'
3355 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3357 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3359 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3361 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3363 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3364 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3367 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3369 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3371 push @$cpuFlags, 'kvm=off' if $kvm_off;
3373 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3374 die "internal error"; # should not happen
3376 push @$cpuFlags, "vendor=${cpu_vendor}"
3377 if $cpu_vendor ne 'default';
3379 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3381 push @$cmd, '-cpu', $cpu;
3383 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3385 push @$cmd, '-S' if $conf->{freeze
};
3387 # set keyboard layout
3388 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3389 push @$cmd, '-k', $kb if $kb;
3392 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3393 #push @$cmd, '-soundhw', 'es1370';
3394 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3396 if($conf->{agent
}) {
3397 my $qgasocket = qmp_socket
($vmid, 1);
3398 my $pciaddr = print_pci_addr
("qga0", $bridges);
3399 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3400 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3401 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3409 for(my $i = 1; $i < $qxlnum; $i++){
3410 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3411 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3414 # assume other OS works like Linux
3415 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3416 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3420 my $pciaddr = print_pci_addr
("spice", $bridges);
3422 my $nodename = PVE
::INotify
::nodename
();
3423 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3424 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3425 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3426 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3427 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3429 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3431 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3432 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3433 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3436 # enable balloon by default, unless explicitly disabled
3437 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3438 $pciaddr = print_pci_addr
("balloon0", $bridges);
3439 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3442 if ($conf->{watchdog
}) {
3443 my $wdopts = parse_watchdog
($conf->{watchdog
});
3444 $pciaddr = print_pci_addr
("watchdog", $bridges);
3445 my $watchdog = $wdopts->{model
} || 'i6300esb';
3446 push @$devices, '-device', "$watchdog$pciaddr";
3447 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3451 my $scsicontroller = {};
3452 my $ahcicontroller = {};
3453 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3455 # Add iscsi initiator name if available
3456 if (my $initiator = get_initiator_name
()) {
3457 push @$devices, '-iscsi', "initiator-name=$initiator";
3460 foreach_drive
($conf, sub {
3461 my ($ds, $drive) = @_;
3463 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3464 push @$vollist, $drive->{file
};
3467 # ignore efidisk here, already added in bios/fw handling code above
3468 return if $drive->{interface
} eq 'efidisk';
3470 $use_virtio = 1 if $ds =~ m/^virtio/;
3472 if (drive_is_cdrom
($drive)) {
3473 if ($bootindex_hash->{d
}) {
3474 $drive->{bootindex
} = $bootindex_hash->{d
};
3475 $bootindex_hash->{d
} += 1;
3478 if ($bootindex_hash->{c
}) {
3479 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3480 $bootindex_hash->{c
} += 1;
3484 if($drive->{interface
} eq 'virtio'){
3485 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3488 if ($drive->{interface
} eq 'scsi') {
3490 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3492 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3493 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3496 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3497 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3498 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3499 } elsif ($drive->{iothread
}) {
3500 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3504 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3505 $queues = ",num_queues=$drive->{queues}";
3508 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3509 $scsicontroller->{$controller}=1;
3512 if ($drive->{interface
} eq 'sata') {
3513 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3514 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3515 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3516 $ahcicontroller->{$controller}=1;
3519 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3520 push @$devices, '-drive',$drive_cmd;
3521 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3524 for (my $i = 0; $i < $MAX_NETS; $i++) {
3525 next if !$conf->{"net$i"};
3526 my $d = parse_net
($conf->{"net$i"});
3529 $use_virtio = 1 if $d->{model
} eq 'virtio';
3531 if ($bootindex_hash->{n
}) {
3532 $d->{bootindex
} = $bootindex_hash->{n
};
3533 $bootindex_hash->{n
} += 1;
3536 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3537 push @$devices, '-netdev', $netdevfull;
3539 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3540 push @$devices, '-device', $netdevicefull;
3545 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3550 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3552 while (my ($k, $v) = each %$bridges) {
3553 $pciaddr = print_pci_addr
("pci.$k");
3554 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3559 if ($conf->{args
}) {
3560 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3564 push @$cmd, @$devices;
3565 push @$cmd, '-rtc', join(',', @$rtcFlags)
3566 if scalar(@$rtcFlags);
3567 push @$cmd, '-machine', join(',', @$machineFlags)
3568 if scalar(@$machineFlags);
3569 push @$cmd, '-global', join(',', @$globalFlags)
3570 if scalar(@$globalFlags);
3572 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3577 return "${var_run_tmpdir}/$vmid.vnc";
3583 my $res = vm_mon_cmd
($vmid, 'query-spice');
3585 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3589 my ($vmid, $qga) = @_;
3590 my $sockettype = $qga ?
'qga' : 'qmp';
3591 return "${var_run_tmpdir}/$vmid.$sockettype";
3596 return "${var_run_tmpdir}/$vmid.pid";
3599 sub vm_devices_list
{
3602 my $res = vm_mon_cmd
($vmid, 'query-pci');
3604 foreach my $pcibus (@$res) {
3605 foreach my $device (@{$pcibus->{devices
}}) {
3606 next if !$device->{'qdev_id'};
3607 if ($device->{'pci_bridge'}) {
3608 $devices->{$device->{'qdev_id'}} = 1;
3609 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3610 next if !$bridge_device->{'qdev_id'};
3611 $devices->{$bridge_device->{'qdev_id'}} = 1;
3612 $devices->{$device->{'qdev_id'}}++;
3615 $devices->{$device->{'qdev_id'}} = 1;
3620 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3621 foreach my $block (@$resblock) {
3622 if($block->{device
} =~ m/^drive-(\S+)/){
3627 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3628 foreach my $mice (@$resmice) {
3629 if ($mice->{name
} eq 'QEMU HID Tablet') {
3630 $devices->{tablet
} = 1;
3635 # for usb devices there is no query-usb
3636 # but we can iterate over the entries in
3637 # qom-list path=/machine/peripheral
3638 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3639 foreach my $per (@$resperipheral) {
3640 if ($per->{name
} =~ m/^usb\d+$/) {
3641 $devices->{$per->{name
}} = 1;
3649 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3651 my $q35 = machine_type_is_q35
($conf);
3653 my $devices_list = vm_devices_list
($vmid);
3654 return 1 if defined($devices_list->{$deviceid});
3656 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3658 if ($deviceid eq 'tablet') {
3660 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3662 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3664 die "usb hotplug currently not reliable\n";
3665 # since we can't reliably hot unplug all added usb devices
3666 # and usb passthrough disables live migration
3667 # we disable usb hotplugging for now
3668 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3670 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3672 qemu_iothread_add
($vmid, $deviceid, $device);
3674 qemu_driveadd
($storecfg, $vmid, $device);
3675 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3677 qemu_deviceadd
($vmid, $devicefull);
3678 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3680 eval { qemu_drivedel
($vmid, $deviceid); };
3685 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3688 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3689 my $pciaddr = print_pci_addr
($deviceid);
3690 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3692 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3694 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3695 qemu_iothread_add
($vmid, $deviceid, $device);
3696 $devicefull .= ",iothread=iothread-$deviceid";
3699 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3700 $devicefull .= ",num_queues=$device->{queues}";
3703 qemu_deviceadd
($vmid, $devicefull);
3704 qemu_deviceaddverify
($vmid, $deviceid);
3706 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3708 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3709 qemu_driveadd
($storecfg, $vmid, $device);
3711 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3712 eval { qemu_deviceadd
($vmid, $devicefull); };
3714 eval { qemu_drivedel
($vmid, $deviceid); };
3719 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3721 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3723 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3724 my $use_old_bios_files = undef;
3725 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3727 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3728 qemu_deviceadd
($vmid, $netdevicefull);
3729 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3731 eval { qemu_netdevdel
($vmid, $deviceid); };
3736 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3739 my $pciaddr = print_pci_addr
($deviceid);
3740 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3742 qemu_deviceadd
($vmid, $devicefull);
3743 qemu_deviceaddverify
($vmid, $deviceid);
3746 die "can't hotplug device '$deviceid'\n";
3752 # fixme: this should raise exceptions on error!
3753 sub vm_deviceunplug
{
3754 my ($vmid, $conf, $deviceid) = @_;
3756 my $devices_list = vm_devices_list
($vmid);
3757 return 1 if !defined($devices_list->{$deviceid});
3759 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3761 if ($deviceid eq 'tablet') {
3763 qemu_devicedel
($vmid, $deviceid);
3765 } elsif ($deviceid =~ m/^usb\d+$/) {
3767 die "usb hotplug currently not reliable\n";
3768 # when unplugging usb devices this way,
3769 # there may be remaining usb controllers/hubs
3770 # so we disable it for now
3771 qemu_devicedel
($vmid, $deviceid);
3772 qemu_devicedelverify
($vmid, $deviceid);
3774 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3776 qemu_devicedel
($vmid, $deviceid);
3777 qemu_devicedelverify
($vmid, $deviceid);
3778 qemu_drivedel
($vmid, $deviceid);
3779 qemu_iothread_del
($conf, $vmid, $deviceid);
3781 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3783 qemu_devicedel
($vmid, $deviceid);
3784 qemu_devicedelverify
($vmid, $deviceid);
3785 qemu_iothread_del
($conf, $vmid, $deviceid);
3787 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3789 qemu_devicedel
($vmid, $deviceid);
3790 qemu_drivedel
($vmid, $deviceid);
3791 qemu_deletescsihw
($conf, $vmid, $deviceid);
3793 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3795 qemu_devicedel
($vmid, $deviceid);
3796 qemu_devicedelverify
($vmid, $deviceid);
3797 qemu_netdevdel
($vmid, $deviceid);
3800 die "can't unplug device '$deviceid'\n";
3806 sub qemu_deviceadd
{
3807 my ($vmid, $devicefull) = @_;
3809 $devicefull = "driver=".$devicefull;
3810 my %options = split(/[=,]/, $devicefull);
3812 vm_mon_cmd
($vmid, "device_add" , %options);
3815 sub qemu_devicedel
{
3816 my ($vmid, $deviceid) = @_;
3818 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3821 sub qemu_iothread_add
{
3822 my($vmid, $deviceid, $device) = @_;
3824 if ($device->{iothread
}) {
3825 my $iothreads = vm_iothreads_list
($vmid);
3826 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3830 sub qemu_iothread_del
{
3831 my($conf, $vmid, $deviceid) = @_;
3833 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3834 if ($device->{iothread
}) {
3835 my $iothreads = vm_iothreads_list
($vmid);
3836 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3840 sub qemu_objectadd
{
3841 my($vmid, $objectid, $qomtype) = @_;
3843 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3848 sub qemu_objectdel
{
3849 my($vmid, $objectid) = @_;
3851 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3857 my ($storecfg, $vmid, $device) = @_;
3859 my $drive = print_drive_full
($storecfg, $vmid, $device);
3860 $drive =~ s/\\/\\\\/g;
3861 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3863 # If the command succeeds qemu prints: "OK
"
3864 return 1 if $ret =~ m/OK/s;
3866 die "adding drive failed
: $ret\n";
3870 my($vmid, $deviceid) = @_;
3872 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3875 return 1 if $ret eq "";
3877 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3878 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3880 die "deleting drive
$deviceid failed
: $ret\n";
3883 sub qemu_deviceaddverify {
3884 my ($vmid, $deviceid) = @_;
3886 for (my $i = 0; $i <= 5; $i++) {
3887 my $devices_list = vm_devices_list($vmid);
3888 return 1 if defined($devices_list->{$deviceid});
3892 die "error on hotplug device
'$deviceid'\n";
3896 sub qemu_devicedelverify {
3897 my ($vmid, $deviceid) = @_;
3899 # need to verify that the device is correctly removed as device_del
3900 # is async and empty return is not reliable
3902 for (my $i = 0; $i <= 5; $i++) {
3903 my $devices_list = vm_devices_list($vmid);
3904 return 1 if !defined($devices_list->{$deviceid});
3908 die "error on hot-unplugging device
'$deviceid'\n";
3911 sub qemu_findorcreatescsihw {
3912 my ($storecfg, $conf, $vmid, $device) = @_;
3914 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3916 my $scsihwid="$controller_prefix$controller";
3917 my $devices_list = vm_devices_list($vmid);
3919 if(!defined($devices_list->{$scsihwid})) {
3920 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3926 sub qemu_deletescsihw {
3927 my ($conf, $vmid, $opt) = @_;
3929 my $device = parse_drive($opt, $conf->{$opt});
3931 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3932 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3936 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3938 my $devices_list = vm_devices_list($vmid);
3939 foreach my $opt (keys %{$devices_list}) {
3940 if (PVE::QemuServer::is_valid_drivename($opt)) {
3941 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3942 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3948 my $scsihwid="scsihw
$controller";
3950 vm_deviceunplug($vmid, $conf, $scsihwid);
3955 sub qemu_add_pci_bridge {
3956 my ($storecfg, $conf, $vmid, $device) = @_;
3962 print_pci_addr($device, $bridges);
3964 while (my ($k, $v) = each %$bridges) {
3967 return 1 if !defined($bridgeid) || $bridgeid < 1;
3969 my $bridge = "pci
.$bridgeid";
3970 my $devices_list = vm_devices_list($vmid);
3972 if (!defined($devices_list->{$bridge})) {
3973 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3979 sub qemu_set_link_status {
3980 my ($vmid, $device, $up) = @_;
3982 vm_mon_cmd($vmid, "set_link
", name => $device,
3983 up => $up ? JSON::true : JSON::false);
3986 sub qemu_netdevadd {
3987 my ($vmid, $conf, $device, $deviceid) = @_;
3989 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3990 my %options = split(/[=,]/, $netdev);
3992 vm_mon_cmd($vmid, "netdev_add
", %options);
3996 sub qemu_netdevdel {
3997 my ($vmid, $deviceid) = @_;
3999 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4002 sub qemu_usb_hotplug {
4003 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4007 # remove the old one first
4008 vm_deviceunplug($vmid, $conf, $deviceid);
4010 # check if xhci controller is necessary and available
4011 if ($device->{usb3}) {
4013 my $devicelist = vm_devices_list($vmid);
4015 if (!$devicelist->{xhci}) {
4016 my $pciaddr = print_pci_addr("xhci
");
4017 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4020 my $d = parse_usb_device($device->{host});
4021 $d->{usb3} = $device->{usb3};
4024 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4027 sub qemu_cpu_hotplug {
4028 my ($vmid, $conf, $vcpus) = @_;
4030 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4033 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4034 $sockets = $conf->{sockets} if $conf->{sockets};
4035 my $cores = $conf->{cores} || 1;
4036 my $maxcpus = $sockets * $cores;
4038 $vcpus = $maxcpus if !$vcpus;
4040 die "you can
't add more vcpus than maxcpus\n"
4041 if $vcpus > $maxcpus;
4043 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4045 if ($vcpus < $currentvcpus) {
4047 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4049 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4050 qemu_devicedel($vmid, "cpu$i");
4052 my $currentrunningvcpus = undef;
4054 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4055 last if scalar(@{$currentrunningvcpus}) == $i-1;
4056 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4060 #update conf after each succesfull cpu unplug
4061 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4062 PVE::QemuConfig->write_config($vmid, $conf);
4065 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4071 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4072 die "vcpus in running vm does not match its configuration\n"
4073 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4075 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4077 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4078 my $cpustr = print_cpu_device($conf, $i);
4079 qemu_deviceadd($vmid, $cpustr);
4082 my $currentrunningvcpus = undef;
4084 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4085 last if scalar(@{$currentrunningvcpus}) == $i;
4086 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4090 #update conf after each succesfull cpu hotplug
4091 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4092 PVE::QemuConfig->write_config($vmid, $conf);
4096 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4097 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4102 sub qemu_block_set_io_throttle {
4103 my ($vmid, $deviceid,
4104 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4105 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4106 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4107 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4109 return if !check_running($vmid) ;
4111 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4113 bps_rd => int($bps_rd),
4114 bps_wr => int($bps_wr),
4116 iops_rd => int($iops_rd),
4117 iops_wr => int($iops_wr),
4118 bps_max => int($bps_max),
4119 bps_rd_max => int($bps_rd_max),
4120 bps_wr_max => int($bps_wr_max),
4121 iops_max => int($iops_max),
4122 iops_rd_max => int($iops_rd_max),
4123 iops_wr_max => int($iops_wr_max),
4124 bps_max_length => int($bps_max_length),
4125 bps_rd_max_length => int($bps_rd_max_length),
4126 bps_wr_max_length => int($bps_wr_max_length),
4127 iops_max_length => int($iops_max_length),
4128 iops_rd_max_length => int($iops_rd_max_length),
4129 iops_wr_max_length => int($iops_wr_max_length),
4134 # old code, only used to shutdown old VM after update
4136 my ($fh, $timeout) = @_;
4138 my $sel = new IO::Select;
4145 while (scalar (@ready = $sel->can_read($timeout))) {
4147 if ($count = $fh->sysread($buf, 8192)) {
4148 if ($buf =~ /^(.*)\(qemu\) $/s) {
4155 if (!defined($count)) {
4162 die "monitor read timeout\n" if !scalar(@ready);
4167 # old code, only used to shutdown old VM after update
4168 sub vm_monitor_command {
4169 my ($vmid, $cmdstr, $nocheck) = @_;
4174 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4176 my $sname = "${var_run_tmpdir}/$vmid.mon";
4178 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
4179 die "unable to connect to VM $vmid socket - $!\n";
4183 # hack: migrate sometime blocks the monitor (when migrate_downtime
4185 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4186 $timeout = 60*60; # 1 hour
4190 my $data = __read_avail($sock, $timeout);
4192 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
4193 die "got unexpected qemu monitor banner\n";
4196 my $sel = new IO::Select;
4199 if (!scalar(my @ready = $sel->can_write($timeout))) {
4200 die "monitor write error - timeout";
4203 my $fullcmd = "$cmdstr\r";
4205 # syslog('info
', "VM $vmid monitor command: $cmdstr");
4208 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
4209 die "monitor write error - $!";
4212 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
4216 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4217 $timeout = 60*60; # 1 hour
4218 } elsif ($cmdstr =~ m/^(eject|change)/) {
4219 $timeout = 60; # note: cdrom mount command is slow
4221 if ($res = __read_avail($sock, $timeout)) {
4223 my @lines = split("\r?\n", $res);
4225 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
4227 $res = join("\n", @lines);
4235 syslog("err", "VM $vmid monitor command failed - $err");
4242 sub qemu_block_resize {
4243 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4245 my $running = check_running($vmid);
4247 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4249 return if !$running;
4251 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4255 sub qemu_volume_snapshot {
4256 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4258 my $running = check_running($vmid);
4260 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4261 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4263 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4267 sub qemu_volume_snapshot_delete {
4268 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4270 my $running = check_running($vmid);
4272 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4273 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4275 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4279 sub set_migration_caps {
4285 "auto-converge" => 1,
4287 "x-rdma-pin-all" => 0,
4292 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4294 for my $supported_capability (@$supported_capabilities) {
4296 capability => $supported_capability->{capability},
4297 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4301 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4304 my $fast_plug_option = {
4312 'vmstatestorage
' => 1,
4315 # hotplug changes in [PENDING]
4316 # $selection hash can be used to only apply specified options, for
4317 # example: { cores => 1 } (only apply changed 'cores
')
4318 # $errors ref is used to return error messages
4319 sub vmconfig_hotplug_pending {
4320 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4322 my $defaults = load_defaults();
4324 # commit values which do not have any impact on running VM first
4325 # Note: those option cannot raise errors, we we do not care about
4326 # $selection and always apply them.
4328 my $add_error = sub {
4329 my ($opt, $msg) = @_;
4330 $errors->{$opt} = "hotplug problem - $msg";
4334 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4335 if ($fast_plug_option->{$opt}) {
4336 $conf->{$opt} = $conf->{pending}->{$opt};
4337 delete $conf->{pending}->{$opt};
4343 PVE::QemuConfig->write_config($vmid, $conf);
4344 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4347 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4349 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4350 while (my ($opt, $force) = each %$pending_delete_hash) {
4351 next if $selection && !$selection->{$opt};
4353 if ($opt eq 'hotplug
') {
4354 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4355 } elsif ($opt eq 'tablet
') {
4356 die "skip\n" if !$hotplug_features->{usb};
4357 if ($defaults->{tablet}) {
4358 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4360 vm_deviceunplug($vmid, $conf, $opt);
4362 } elsif ($opt =~ m/^usb\d+/) {
4364 # since we cannot reliably hot unplug usb devices
4365 # we are disabling it
4366 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4367 vm_deviceunplug($vmid, $conf, $opt);
4368 } elsif ($opt eq 'vcpus
') {
4369 die "skip\n" if !$hotplug_features->{cpu};
4370 qemu_cpu_hotplug($vmid, $conf, undef);
4371 } elsif ($opt eq 'balloon
') {
4372 # enable balloon device is not hotpluggable
4373 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4374 } elsif ($fast_plug_option->{$opt}) {
4376 } elsif ($opt =~ m/^net(\d+)$/) {
4377 die "skip\n" if !$hotplug_features->{network};
4378 vm_deviceunplug($vmid, $conf, $opt);
4379 } elsif (is_valid_drivename($opt)) {
4380 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4381 vm_deviceunplug($vmid, $conf, $opt);
4382 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4383 } elsif ($opt =~ m/^memory$/) {
4384 die "skip\n" if !$hotplug_features->{memory};
4385 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4386 } elsif ($opt eq 'cpuunits
') {
4387 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4388 } elsif ($opt eq 'cpulimit
') {
4389 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4395 &$add_error($opt, $err) if $err ne "skip\n";
4397 # save new config if hotplug was successful
4398 delete $conf->{$opt};
4399 vmconfig_undelete_pending_option($conf, $opt);
4400 PVE::QemuConfig->write_config($vmid, $conf);
4401 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4405 my $apply_pending_cloudinit;
4406 $apply_pending_cloudinit = sub {
4407 my ($key, $value) = @_;
4408 $apply_pending_cloudinit = sub {}; # once is enough
4410 my @cloudinit_opts = keys %$confdesc_cloudinit;
4411 foreach my $opt (keys %{$conf->{pending}}) {
4412 next if !grep { $_ eq $opt } @cloudinit_opts;
4413 $conf->{$opt} = delete $conf->{pending}->{$opt};
4416 my $new_conf = { %$conf };
4417 $new_conf->{$key} = $value;
4418 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4421 foreach my $opt (keys %{$conf->{pending}}) {
4422 next if $selection && !$selection->{$opt};
4423 my $value = $conf->{pending}->{$opt};
4425 if ($opt eq 'hotplug
') {
4426 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4427 } elsif ($opt eq 'tablet
') {
4428 die "skip\n" if !$hotplug_features->{usb};
4430 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4431 } elsif ($value == 0) {
4432 vm_deviceunplug($vmid, $conf, $opt);
4434 } elsif ($opt =~ m/^usb\d+$/) {
4436 # since we cannot reliably hot unplug usb devices
4437 # we are disabling it
4438 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4439 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4440 die "skip\n" if !$d;
4441 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4442 } elsif ($opt eq 'vcpus
') {
4443 die "skip\n" if !$hotplug_features->{cpu};
4444 qemu_cpu_hotplug($vmid, $conf, $value);
4445 } elsif ($opt eq 'balloon
') {
4446 # enable/disable balloning device is not hotpluggable
4447 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4448 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4449 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4451 # allow manual ballooning if shares is set to zero
4452 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4453 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4454 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4456 } elsif ($opt =~ m/^net(\d+)$/) {
4457 # some changes can be done without hotplug
4458 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4459 $vmid, $opt, $value);
4460 } elsif (is_valid_drivename($opt)) {
4461 # some changes can be done without hotplug
4462 my $drive = parse_drive($opt, $value);
4463 if (drive_is_cloudinit($drive)) {
4464 &$apply_pending_cloudinit($opt, $value);
4466 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4467 $vmid, $opt, $value, 1);
4468 } elsif ($opt =~ m/^memory$/) { #dimms
4469 die "skip\n" if !$hotplug_features->{memory};
4470 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4471 } elsif ($opt eq 'cpuunits
') {
4472 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4473 } elsif ($opt eq 'cpulimit
') {
4474 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4475 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4477 die "skip\n"; # skip non-hot-pluggable options
4481 &$add_error($opt, $err) if $err ne "skip\n";
4483 # save new config if hotplug was successful
4484 $conf->{$opt} = $value;
4485 delete $conf->{pending}->{$opt};
4486 PVE::QemuConfig->write_config($vmid, $conf);
4487 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4492 sub try_deallocate_drive {
4493 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4495 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4496 my $volid = $drive->{file};
4497 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4498 my $sid = PVE::Storage::parse_volume_id($volid);
4499 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4501 # check if the disk is really unused
4502 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4503 if is_volume_in_use($storecfg, $conf, $key, $volid);
4504 PVE::Storage::vdisk_free($storecfg, $volid);
4507 # If vm is not owner of this disk remove from config
4515 sub vmconfig_delete_or_detach_drive {
4516 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4518 my $drive = parse_drive($opt, $conf->{$opt});
4520 my $rpcenv = PVE::RPCEnvironment::get();
4521 my $authuser = $rpcenv->get_user();
4524 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4525 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4527 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4531 sub vmconfig_apply_pending {
4532 my ($vmid, $conf, $storecfg) = @_;
4536 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4537 while (my ($opt, $force) = each %$pending_delete_hash) {
4538 die "internal error" if $opt =~ m/^unused/;
4539 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4540 if (!defined($conf->{$opt})) {
4541 vmconfig_undelete_pending_option($conf, $opt);
4542 PVE::QemuConfig->write_config($vmid, $conf);
4543 } elsif (is_valid_drivename($opt)) {
4544 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4545 vmconfig_undelete_pending_option($conf, $opt);
4546 delete $conf->{$opt};
4547 PVE::QemuConfig->write_config($vmid, $conf);
4549 vmconfig_undelete_pending_option($conf, $opt);
4550 delete $conf->{$opt};
4551 PVE::QemuConfig->write_config($vmid, $conf);
4555 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4557 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4558 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4560 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4561 # skip if nothing changed
4562 } elsif (is_valid_drivename($opt)) {
4563 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4564 if defined($conf->{$opt});
4565 $conf->{$opt} = $conf->{pending}->{$opt};
4567 $conf->{$opt} = $conf->{pending}->{$opt};
4570 delete $conf->{pending}->{$opt};
4571 PVE::QemuConfig->write_config($vmid, $conf);
4575 my $safe_num_ne = sub {
4578 return 0 if !defined($a) && !defined($b);
4579 return 1 if !defined($a);
4580 return 1 if !defined($b);
4585 my $safe_string_ne = sub {
4588 return 0 if !defined($a) && !defined($b);
4589 return 1 if !defined($a);
4590 return 1 if !defined($b);
4595 sub vmconfig_update_net {
4596 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4598 my $newnet = parse_net($value);
4600 if ($conf->{$opt}) {
4601 my $oldnet = parse_net($conf->{$opt});
4603 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4604 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4605 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4606 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4608 # for non online change, we try to hot-unplug
4609 die "skip\n" if !$hotplug;
4610 vm_deviceunplug($vmid, $conf, $opt);
4613 die "internal error" if $opt !~ m/net(\d+)/;
4614 my $iface = "tap${vmid}i$1";
4616 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4617 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4618 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4619 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4620 PVE::Network::tap_unplug($iface);
4621 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4622 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4623 # Rate can be applied on its own but any change above needs to
4624 # include the rate in tap_plug since OVS resets everything.
4625 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4628 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4629 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4637 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4643 sub vmconfig_update_disk {
4644 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4646 # fixme: do we need force?
4648 my $drive = parse_drive($opt, $value);
4650 if ($conf->{$opt}) {
4652 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4654 my $media = $drive->{media} || 'disk
';
4655 my $oldmedia = $old_drive->{media} || 'disk
';
4656 die "unable to change media type\n" if $media ne $oldmedia;
4658 if (!drive_is_cdrom($old_drive)) {
4660 if ($drive->{file} ne $old_drive->{file}) {
4662 die "skip\n" if !$hotplug;
4664 # unplug and register as unused
4665 vm_deviceunplug($vmid, $conf, $opt);
4666 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4669 # update existing disk
4671 # skip non hotpluggable value
4672 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4673 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4674 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4675 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4680 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4681 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4682 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4683 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4684 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4685 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4686 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4687 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4688 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4689 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4690 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4691 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4692 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4693 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4694 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4695 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4696 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4697 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4699 qemu_block_set_io_throttle($vmid,"drive-$opt",
4700 ($drive->{mbps} || 0)*1024*1024,
4701 ($drive->{mbps_rd} || 0)*1024*1024,
4702 ($drive->{mbps_wr} || 0)*1024*1024,
4703 $drive->{iops} || 0,
4704 $drive->{iops_rd} || 0,
4705 $drive->{iops_wr} || 0,
4706 ($drive->{mbps_max} || 0)*1024*1024,
4707 ($drive->{mbps_rd_max} || 0)*1024*1024,
4708 ($drive->{mbps_wr_max} || 0)*1024*1024,
4709 $drive->{iops_max} || 0,
4710 $drive->{iops_rd_max} || 0,
4711 $drive->{iops_wr_max} || 0,
4712 $drive->{bps_max_length} || 1,
4713 $drive->{bps_rd_max_length} || 1,
4714 $drive->{bps_wr_max_length} || 1,
4715 $drive->{iops_max_length} || 1,
4716 $drive->{iops_rd_max_length} || 1,
4717 $drive->{iops_wr_max_length} || 1);
4726 if ($drive->{file} eq 'none
') {
4727 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4728 if (drive_is_cloudinit($old_drive)) {
4729 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4732 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4733 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4734 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4742 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4744 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4745 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4749 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4750 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4752 PVE::QemuConfig->lock_config($vmid, sub {
4753 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4755 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4757 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4759 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4761 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4762 vmconfig_apply_pending($vmid, $conf, $storecfg);
4763 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4766 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4768 my $defaults = load_defaults();
4770 # set environment variable useful inside network script
4771 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4773 my $local_volumes = {};
4775 if ($targetstorage) {
4776 foreach_drive($conf, sub {
4777 my ($ds, $drive) = @_;
4779 return if drive_is_cdrom($drive);
4781 my $volid = $drive->{file};
4785 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4787 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4788 return if $scfg->{shared};
4789 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4794 foreach my $opt (sort keys %$local_volumes) {
4796 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4797 my $drive = parse_drive($opt, $conf->{$opt});
4799 #if remote storage is specified, use default format
4800 if ($targetstorage && $targetstorage ne "1") {
4801 $storeid = $targetstorage;
4802 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4803 $format = $defFormat;
4805 #else we use same format than original
4806 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4807 $format = qemu_img_format($scfg, $volid);
4810 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4811 my $newdrive = $drive;
4812 $newdrive->{format} = $format;
4813 $newdrive->{file} = $newvolid;
4814 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4815 $local_volumes->{$opt} = $drivestr;
4816 #pass drive to conf for command line
4817 $conf->{$opt} = $drivestr;
4821 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4823 my $migrate_port = 0;
4826 if ($statefile eq 'tcp
') {
4827 my $localip = "localhost";
4828 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4829 my $nodename = PVE::INotify::nodename();
4831 if (!defined($migration_type)) {
4832 if (defined($datacenterconf->{migration}->{type})) {
4833 $migration_type = $datacenterconf->{migration}->{type};
4835 $migration_type = 'secure
';
4839 if ($migration_type eq 'insecure
') {
4840 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4841 if ($migrate_network_addr) {
4842 $localip = $migrate_network_addr;
4844 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4847 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4850 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4851 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4852 $migrate_uri = "tcp:${localip}:${migrate_port}";
4853 push @$cmd, '-incoming
', $migrate_uri;
4856 } elsif ($statefile eq 'unix
') {
4857 # should be default for secure migrations as a ssh TCP forward
4858 # tunnel is not deterministic reliable ready and fails regurarly
4859 # to set up in time, so use UNIX socket forwards
4860 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4861 unlink $socket_addr;
4863 $migrate_uri = "unix:$socket_addr";
4865 push @$cmd, '-incoming
', $migrate_uri;
4869 push @$cmd, '-loadstate
', $statefile;
4876 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4877 my $d = parse_hostpci($conf->{"hostpci$i"});
4879 my $pcidevices = $d->{pciid};
4880 foreach my $pcidevice (@$pcidevices) {
4881 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4883 my $info = pci_device_info("0000:$pciid");
4884 die "IOMMU not present\n" if !check_iommu_support();
4885 die "no pci device info for device '$pciid'\n" if !$info;
4886 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4887 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4891 PVE::Storage::activate_volumes($storecfg, $vollist);
4893 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4895 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4896 eval { run_command($cmd); };
4899 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4900 : $defaults->{cpuunits};
4902 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4903 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4906 Slice => 'qemu
.slice
',
4908 CPUShares => $cpuunits
4911 if (my $cpulimit = $conf->{cpulimit}) {
4912 $properties{CPUQuota} = int($cpulimit * 100);
4914 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4916 if ($conf->{hugepages}) {
4919 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4920 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4922 PVE::QemuServer::Memory::hugepages_mount();
4923 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4926 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4927 run_command($cmd, %run_params);
4931 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4935 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4937 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4941 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4942 run_command($cmd, %run_params);
4947 # deactivate volumes if start fails
4948 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4949 die "start failed: $err";
4952 print "migration listens on $migrate_uri\n" if $migrate_uri;
4954 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4955 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4959 #start nbd server for storage migration
4960 if ($targetstorage) {
4961 my $nodename = PVE::INotify::nodename();
4962 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4963 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4964 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4965 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4967 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4969 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4971 foreach my $opt (sort keys %$local_volumes) {
4972 my $volid = $local_volumes->{$opt};
4973 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4974 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4975 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4979 if ($migratedfrom) {
4981 set_migration_caps($vmid);
4986 print "spice listens on port $spice_port\n";
4987 if ($spice_ticket) {
4988 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4989 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4994 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4995 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4996 if $conf->{balloon};
4999 foreach my $opt (keys %$conf) {
5000 next if $opt !~ m/^net\d+$/;
5001 my $nicconf = parse_net($conf->{$opt});
5002 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5006 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5007 path => "machine/peripheral/balloon0",
5008 property => "guest-stats-polling-interval",
5009 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5015 my ($vmid, $execute, %params) = @_;
5017 my $cmd = { execute => $execute, arguments => \%params };
5018 vm_qmp_command($vmid, $cmd);
5021 sub vm_mon_cmd_nocheck {
5022 my ($vmid, $execute, %params) = @_;
5024 my $cmd = { execute => $execute, arguments => \%params };
5025 vm_qmp_command($vmid, $cmd, 1);
5028 sub vm_qmp_command {
5029 my ($vmid, $cmd, $nocheck) = @_;
5034 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5035 $timeout = $cmd->{arguments}->{timeout};
5036 delete $cmd->{arguments}->{timeout};
5040 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5041 my $sname = qmp_socket($vmid);
5042 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5043 my $qmpclient = PVE::QMPClient->new();
5045 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5046 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
5047 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
5048 if scalar(%{$cmd->{arguments}});
5049 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
5051 die "unable to
open monitor
socket\n";
5055 syslog("err
", "VM
$vmid qmp command failed
- $err");
5062 sub vm_human_monitor_command {
5063 my ($vmid, $cmdline) = @_;
5068 execute => 'human-monitor-command',
5069 arguments => { 'command-line' => $cmdline},
5072 return vm_qmp_command($vmid, $cmd);
5075 sub vm_commandline {
5076 my ($storecfg, $vmid) = @_;
5078 my $conf = PVE::QemuConfig->load_config($vmid);
5080 my $defaults = load_defaults();
5082 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5084 return PVE::Tools::cmd2string($cmd);
5088 my ($vmid, $skiplock) = @_;
5090 PVE::QemuConfig->lock_config($vmid, sub {
5092 my $conf = PVE::QemuConfig->load_config($vmid);
5094 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5096 vm_mon_cmd($vmid, "system_reset
");
5100 sub get_vm_volumes {
5104 foreach_volid($conf, sub {
5105 my ($volid, $attr) = @_;
5107 return if $volid =~ m|^/|;
5109 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5112 push @$vollist, $volid;
5118 sub vm_stop_cleanup {
5119 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5124 my $vollist = get_vm_volumes($conf);
5125 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5128 foreach my $ext (qw(mon qmp pid vnc qga)) {
5129 unlink "/var/run/qemu-server/${vmid}.$ext";
5132 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5134 warn $@ if $@; # avoid errors - just warn
5137 # Note: use $nockeck to skip tests if VM configuration file exists.
5138 # We need that when migration VMs to other nodes (files already moved)
5139 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5141 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5143 $force = 1 if !defined($force) && !$shutdown;
5146 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5147 kill 15, $pid if $pid;
5148 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5149 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5153 PVE
::QemuConfig-
>lock_config($vmid, sub {
5155 my $pid = check_running
($vmid, $nocheck);
5160 $conf = PVE
::QemuConfig-
>load_config($vmid);
5161 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5162 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5163 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5164 $timeout = $opts->{down
} if $opts->{down
};
5168 $timeout = 60 if !defined($timeout);
5172 if (defined($conf) && $conf->{agent
}) {
5173 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5175 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5178 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5185 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5190 if ($count >= $timeout) {
5192 warn "VM still running - terminating now with SIGTERM\n";
5195 die "VM quit/powerdown failed - got timeout\n";
5198 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5203 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5206 die "VM quit/powerdown failed\n";
5214 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5219 if ($count >= $timeout) {
5220 warn "VM still running - terminating now with SIGKILL\n";
5225 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5230 my ($vmid, $skiplock) = @_;
5232 PVE
::QemuConfig-
>lock_config($vmid, sub {
5234 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5236 PVE
::QemuConfig-
>check_lock($conf)
5237 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5239 vm_mon_cmd
($vmid, "stop");
5244 my ($vmid, $skiplock, $nocheck) = @_;
5246 PVE
::QemuConfig-
>lock_config($vmid, sub {
5250 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5252 PVE
::QemuConfig-
>check_lock($conf)
5253 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5255 vm_mon_cmd
($vmid, "cont");
5258 vm_mon_cmd_nocheck
($vmid, "cont");
5264 my ($vmid, $skiplock, $key) = @_;
5266 PVE
::QemuConfig-
>lock_config($vmid, sub {
5268 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5270 # there is no qmp command, so we use the human monitor command
5271 vm_human_monitor_command
($vmid, "sendkey $key");
5276 my ($storecfg, $vmid, $skiplock) = @_;
5278 PVE
::QemuConfig-
>lock_config($vmid, sub {
5280 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5282 if (!check_running
($vmid)) {
5283 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5285 die "VM $vmid is running - destroy failed\n";
5293 my ($filename, $buf) = @_;
5295 my $fh = IO
::File-
>new($filename, "w");
5296 return undef if !$fh;
5298 my $res = print $fh $buf;
5305 sub pci_device_info
{
5310 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5311 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5313 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5314 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5316 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5317 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5319 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5320 return undef if !defined($product) || $product !~ s/^0x//;
5325 product
=> $product,
5331 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5340 my $name = $dev->{name
};
5342 my $fn = "$pcisysfs/devices/$name/reset";
5344 return file_write
($fn, "1");
5347 sub pci_dev_bind_to_vfio
{
5350 my $name = $dev->{name
};
5352 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5354 if (!-d
$vfio_basedir) {
5355 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5357 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5359 my $testdir = "$vfio_basedir/$name";
5360 return 1 if -d
$testdir;
5362 my $data = "$dev->{vendor} $dev->{product}";
5363 return undef if !file_write
("$vfio_basedir/new_id", $data);
5365 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5366 if (!file_write
($fn, $name)) {
5367 return undef if -f
$fn;
5370 $fn = "$vfio_basedir/bind";
5371 if (! -d
$testdir) {
5372 return undef if !file_write
($fn, $name);
5378 sub pci_dev_group_bind_to_vfio
{
5381 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5383 if (!-d
$vfio_basedir) {
5384 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5386 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5388 # get IOMMU group devices
5389 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5390 my @devs = grep /^0000:/, readdir($D);
5393 foreach my $pciid (@devs) {
5394 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5396 # pci bridges, switches or root ports are not supported
5397 # they have a pci_bus subdirectory so skip them
5398 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5400 my $info = pci_device_info
($1);
5401 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5407 # vzdump restore implementaion
5409 sub tar_archive_read_firstfile
{
5410 my $archive = shift;
5412 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5414 # try to detect archive type first
5415 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5416 die "unable to open file '$archive'\n";
5417 my $firstfile = <$fh>;
5421 die "ERROR: archive contaions no data\n" if !$firstfile;
5427 sub tar_restore_cleanup
{
5428 my ($storecfg, $statfile) = @_;
5430 print STDERR
"starting cleanup\n";
5432 if (my $fd = IO
::File-
>new($statfile, "r")) {
5433 while (defined(my $line = <$fd>)) {
5434 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5437 if ($volid =~ m
|^/|) {
5438 unlink $volid || die 'unlink failed\n';
5440 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5442 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5444 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5446 print STDERR
"unable to parse line in statfile - $line";
5453 sub restore_archive
{
5454 my ($archive, $vmid, $user, $opts) = @_;
5456 my $format = $opts->{format
};
5459 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5460 $format = 'tar' if !$format;
5462 } elsif ($archive =~ m/\.tar$/) {
5463 $format = 'tar' if !$format;
5464 } elsif ($archive =~ m/.tar.lzo$/) {
5465 $format = 'tar' if !$format;
5467 } elsif ($archive =~ m/\.vma$/) {
5468 $format = 'vma' if !$format;
5469 } elsif ($archive =~ m/\.vma\.gz$/) {
5470 $format = 'vma' if !$format;
5472 } elsif ($archive =~ m/\.vma\.lzo$/) {
5473 $format = 'vma' if !$format;
5476 $format = 'vma' if !$format; # default
5479 # try to detect archive format
5480 if ($format eq 'tar') {
5481 return restore_tar_archive
($archive, $vmid, $user, $opts);
5483 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5487 sub restore_update_config_line
{
5488 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5490 return if $line =~ m/^\#qmdump\#/;
5491 return if $line =~ m/^\#vzdump\#/;
5492 return if $line =~ m/^lock:/;
5493 return if $line =~ m/^unused\d+:/;
5494 return if $line =~ m/^parent:/;
5495 return if $line =~ m/^template:/; # restored VM is never a template
5497 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5498 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5499 # try to convert old 1.X settings
5500 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5501 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5502 my ($model, $macaddr) = split(/\=/, $devconfig);
5503 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5506 bridge
=> "vmbr$ind",
5507 macaddr
=> $macaddr,
5509 my $netstr = print_net
($net);
5511 print $outfd "net$cookie->{netcount}: $netstr\n";
5512 $cookie->{netcount
}++;
5514 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5515 my ($id, $netstr) = ($1, $2);
5516 my $net = parse_net
($netstr);
5517 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5518 $netstr = print_net
($net);
5519 print $outfd "$id: $netstr\n";
5520 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5523 my $di = parse_drive
($virtdev, $value);
5524 if (defined($di->{backup
}) && !$di->{backup
}) {
5525 print $outfd "#$line";
5526 } elsif ($map->{$virtdev}) {
5527 delete $di->{format
}; # format can change on restore
5528 $di->{file
} = $map->{$virtdev};
5529 $value = print_drive
($vmid, $di);
5530 print $outfd "$virtdev: $value\n";
5534 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5535 my ($uuid, $uuid_str);
5536 UUID
::generate
($uuid);
5537 UUID
::unparse
($uuid, $uuid_str);
5538 my $smbios1 = parse_smbios1
($2);
5539 $smbios1->{uuid
} = $uuid_str;
5540 print $outfd $1.print_smbios1
($smbios1)."\n";
5547 my ($cfg, $vmid) = @_;
5549 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5551 my $volid_hash = {};
5552 foreach my $storeid (keys %$info) {
5553 foreach my $item (@{$info->{$storeid}}) {
5554 next if !($item->{volid
} && $item->{size
});
5555 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5556 $volid_hash->{$item->{volid
}} = $item;
5563 sub is_volume_in_use
{
5564 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5566 my $path = PVE
::Storage
::path
($storecfg, $volid);
5568 my $scan_config = sub {
5569 my ($cref, $snapname) = @_;
5571 foreach my $key (keys %$cref) {
5572 my $value = $cref->{$key};
5573 if (is_valid_drivename
($key)) {
5574 next if $skip_drive && $key eq $skip_drive;
5575 my $drive = parse_drive
($key, $value);
5576 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5577 return 1 if $volid eq $drive->{file
};
5578 if ($drive->{file
} =~ m!^/!) {
5579 return 1 if $drive->{file
} eq $path;
5581 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5583 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5585 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5593 return 1 if &$scan_config($conf);
5597 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5598 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5604 sub update_disksize
{
5605 my ($vmid, $conf, $volid_hash) = @_;
5609 # used and unused disks
5610 my $referenced = {};
5612 # Note: it is allowed to define multiple storages with same path (alias), so
5613 # we need to check both 'volid' and real 'path' (two different volid can point
5614 # to the same path).
5616 my $referencedpath = {};
5619 foreach my $opt (keys %$conf) {
5620 if (is_valid_drivename
($opt)) {
5621 my $drive = parse_drive
($opt, $conf->{$opt});
5622 my $volid = $drive->{file
};
5625 $referenced->{$volid} = 1;
5626 if ($volid_hash->{$volid} &&
5627 (my $path = $volid_hash->{$volid}->{path
})) {
5628 $referencedpath->{$path} = 1;
5631 next if drive_is_cdrom
($drive);
5632 next if !$volid_hash->{$volid};
5634 $drive->{size
} = $volid_hash->{$volid}->{size
};
5635 my $new = print_drive
($vmid, $drive);
5636 if ($new ne $conf->{$opt}) {
5638 $conf->{$opt} = $new;
5643 # remove 'unusedX' entry if volume is used
5644 foreach my $opt (keys %$conf) {
5645 next if $opt !~ m/^unused\d+$/;
5646 my $volid = $conf->{$opt};
5647 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5648 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5650 delete $conf->{$opt};
5653 $referenced->{$volid} = 1;
5654 $referencedpath->{$path} = 1 if $path;
5657 foreach my $volid (sort keys %$volid_hash) {
5658 next if $volid =~ m/vm-$vmid-state-/;
5659 next if $referenced->{$volid};
5660 my $path = $volid_hash->{$volid}->{path
};
5661 next if !$path; # just to be sure
5662 next if $referencedpath->{$path};
5664 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5665 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5672 my ($vmid, $nolock) = @_;
5674 my $cfg = PVE
::Storage
::config
();
5676 my $volid_hash = scan_volids
($cfg, $vmid);
5678 my $updatefn = sub {
5681 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5683 PVE
::QemuConfig-
>check_lock($conf);
5686 foreach my $volid (keys %$volid_hash) {
5687 my $info = $volid_hash->{$volid};
5688 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5691 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5693 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5696 if (defined($vmid)) {
5700 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5703 my $vmlist = config_list
();
5704 foreach my $vmid (keys %$vmlist) {
5708 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5714 sub restore_vma_archive
{
5715 my ($archive, $vmid, $user, $opts, $comp) = @_;
5717 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5718 my $readfrom = $archive;
5723 my $qarchive = PVE
::Tools
::shellquote
($archive);
5724 if ($comp eq 'gzip') {
5725 $uncomp = "zcat $qarchive|";
5726 } elsif ($comp eq 'lzop') {
5727 $uncomp = "lzop -d -c $qarchive|";
5729 die "unknown compression method '$comp'\n";
5734 my $tmpdir = "/var/tmp/vzdumptmp$$";
5737 # disable interrupts (always do cleanups)
5741 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5743 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5744 POSIX
::mkfifo
($mapfifo, 0600);
5747 my $openfifo = sub {
5748 open($fifofh, '>', $mapfifo) || die $!;
5751 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5758 my $rpcenv = PVE
::RPCEnvironment
::get
();
5760 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5761 my $tmpfn = "$conffile.$$.tmp";
5763 # Note: $oldconf is undef if VM does not exists
5764 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5765 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5767 my $print_devmap = sub {
5768 my $virtdev_hash = {};
5770 my $cfgfn = "$tmpdir/qemu-server.conf";
5772 # we can read the config - that is already extracted
5773 my $fh = IO
::File-
>new($cfgfn, "r") ||
5774 "unable to read qemu-server.conf - $!\n";
5776 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5778 my $pve_firewall_dir = '/etc/pve/firewall';
5779 mkdir $pve_firewall_dir; # make sure the dir exists
5780 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5783 while (defined(my $line = <$fh>)) {
5784 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5785 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5786 die "archive does not contain data for drive '$virtdev'\n"
5787 if !$devinfo->{$devname};
5788 if (defined($opts->{storage
})) {
5789 $storeid = $opts->{storage
} || 'local';
5790 } elsif (!$storeid) {
5793 $format = 'raw' if !$format;
5794 $devinfo->{$devname}->{devname
} = $devname;
5795 $devinfo->{$devname}->{virtdev
} = $virtdev;
5796 $devinfo->{$devname}->{format
} = $format;
5797 $devinfo->{$devname}->{storeid
} = $storeid;
5799 # check permission on storage
5800 my $pool = $opts->{pool
}; # todo: do we need that?
5801 if ($user ne 'root@pam') {
5802 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5805 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5809 foreach my $devname (keys %$devinfo) {
5810 die "found no device mapping information for device '$devname'\n"
5811 if !$devinfo->{$devname}->{virtdev
};
5814 my $cfg = PVE
::Storage
::config
();
5816 # create empty/temp config
5818 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5819 foreach_drive
($oldconf, sub {
5820 my ($ds, $drive) = @_;
5822 return if drive_is_cdrom
($drive);
5824 my $volid = $drive->{file
};
5826 return if !$volid || $volid =~ m
|^/|;
5828 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5829 return if !$path || !$owner || ($owner != $vmid);
5831 # Note: only delete disk we want to restore
5832 # other volumes will become unused
5833 if ($virtdev_hash->{$ds}) {
5834 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5841 # delete vmstate files
5842 # since after the restore we have no snapshots anymore
5843 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5844 my $snap = $oldconf->{snapshots
}->{$snapname};
5845 if ($snap->{vmstate
}) {
5846 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5855 foreach my $virtdev (sort keys %$virtdev_hash) {
5856 my $d = $virtdev_hash->{$virtdev};
5857 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5858 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5860 # test if requested format is supported
5861 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5862 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5863 $d->{format
} = $defFormat if !$supported;
5865 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5866 $d->{format
}, undef, $alloc_size);
5867 print STDERR
"new volume ID is '$volid'\n";
5868 $d->{volid
} = $volid;
5869 my $path = PVE
::Storage
::path
($cfg, $volid);
5871 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5873 my $write_zeros = 1;
5874 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5878 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5880 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5881 $map->{$virtdev} = $volid;
5884 $fh->seek(0, 0) || die "seek failed - $!\n";
5886 my $outfd = new IO
::File
($tmpfn, "w") ||
5887 die "unable to write config for VM $vmid\n";
5889 my $cookie = { netcount
=> 0 };
5890 while (defined(my $line = <$fh>)) {
5891 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5904 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5905 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5907 $oldtimeout = alarm($timeout);
5914 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5915 my ($dev_id, $size, $devname) = ($1, $2, $3);
5916 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5917 } elsif ($line =~ m/^CTIME: /) {
5918 # we correctly received the vma config, so we can disable
5919 # the timeout now for disk allocation (set to 10 minutes, so
5920 # that we always timeout if something goes wrong)
5923 print $fifofh "done\n";
5924 my $tmp = $oldtimeout || 0;
5925 $oldtimeout = undef;
5931 print "restore vma archive: $cmd\n";
5932 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5936 alarm($oldtimeout) if $oldtimeout;
5939 foreach my $devname (keys %$devinfo) {
5940 my $volid = $devinfo->{$devname}->{volid
};
5941 push @$vollist, $volid if $volid;
5944 my $cfg = PVE
::Storage
::config
();
5945 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5953 foreach my $devname (keys %$devinfo) {
5954 my $volid = $devinfo->{$devname}->{volid
};
5957 if ($volid =~ m
|^/|) {
5958 unlink $volid || die 'unlink failed\n';
5960 PVE
::Storage
::vdisk_free
($cfg, $volid);
5962 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5964 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5971 rename($tmpfn, $conffile) ||
5972 die "unable to commit configuration file '$conffile'\n";
5974 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5976 eval { rescan
($vmid, 1); };
5980 sub restore_tar_archive
{
5981 my ($archive, $vmid, $user, $opts) = @_;
5983 if ($archive ne '-') {
5984 my $firstfile = tar_archive_read_firstfile
($archive);
5985 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5986 if $firstfile ne 'qemu-server.conf';
5989 my $storecfg = PVE
::Storage
::config
();
5991 # destroy existing data - keep empty config
5992 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5993 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5995 my $tocmd = "/usr/lib/qemu-server/qmextract";
5997 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5998 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5999 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6000 $tocmd .= ' --info' if $opts->{info
};
6002 # tar option "xf" does not autodetect compression when read from STDIN,
6003 # so we pipe to zcat
6004 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6005 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6007 my $tmpdir = "/var/tmp/vzdumptmp$$";
6010 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6011 local $ENV{VZDUMP_VMID
} = $vmid;
6012 local $ENV{VZDUMP_USER
} = $user;
6014 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6015 my $tmpfn = "$conffile.$$.tmp";
6017 # disable interrupts (always do cleanups)
6021 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6029 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6031 if ($archive eq '-') {
6032 print "extracting archive from STDIN\n";
6033 run_command
($cmd, input
=> "<&STDIN");
6035 print "extracting archive '$archive'\n";
6039 return if $opts->{info
};
6043 my $statfile = "$tmpdir/qmrestore.stat";
6044 if (my $fd = IO
::File-
>new($statfile, "r")) {
6045 while (defined (my $line = <$fd>)) {
6046 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6047 $map->{$1} = $2 if $1;
6049 print STDERR
"unable to parse line in statfile - $line\n";
6055 my $confsrc = "$tmpdir/qemu-server.conf";
6057 my $srcfd = new IO
::File
($confsrc, "r") ||
6058 die "unable to open file '$confsrc'\n";
6060 my $outfd = new IO
::File
($tmpfn, "w") ||
6061 die "unable to write config for VM $vmid\n";
6063 my $cookie = { netcount
=> 0 };
6064 while (defined (my $line = <$srcfd>)) {
6065 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6077 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6084 rename $tmpfn, $conffile ||
6085 die "unable to commit configuration file '$conffile'\n";
6087 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6089 eval { rescan
($vmid, 1); };
6093 sub foreach_storage_used_by_vm
{
6094 my ($conf, $func) = @_;
6098 foreach_drive
($conf, sub {
6099 my ($ds, $drive) = @_;
6100 return if drive_is_cdrom
($drive);
6102 my $volid = $drive->{file
};
6104 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6105 $sidhash->{$sid} = $sid if $sid;
6108 foreach my $sid (sort keys %$sidhash) {
6113 sub do_snapshots_with_qemu
{
6114 my ($storecfg, $volid) = @_;
6116 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6118 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6119 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6123 if ($volid =~ m/\.(qcow2|qed)$/){
6130 sub qga_check_running
{
6133 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6135 warn "Qemu Guest Agent is not running - $@";
6141 sub template_create
{
6142 my ($vmid, $conf, $disk) = @_;
6144 my $storecfg = PVE
::Storage
::config
();
6146 foreach_drive
($conf, sub {
6147 my ($ds, $drive) = @_;
6149 return if drive_is_cdrom
($drive);
6150 return if $disk && $ds ne $disk;
6152 my $volid = $drive->{file
};
6153 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6155 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6156 $drive->{file
} = $voliddst;
6157 $conf->{$ds} = print_drive
($vmid, $drive);
6158 PVE
::QemuConfig-
>write_config($vmid, $conf);
6162 sub qemu_img_convert
{
6163 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6165 my $storecfg = PVE
::Storage
::config
();
6166 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6167 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6169 if ($src_storeid && $dst_storeid) {
6171 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6173 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6174 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6176 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6177 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6179 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6180 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6183 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6184 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6185 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6186 if ($is_zero_initialized) {
6187 push @$cmd, "zeroinit:$dst_path";
6189 push @$cmd, $dst_path;
6194 if($line =~ m/\((\S+)\/100\
%\)/){
6196 my $transferred = int($size * $percent / 100);
6197 my $remaining = $size - $transferred;
6199 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6204 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6206 die "copy failed: $err" if $err;
6210 sub qemu_img_format
{
6211 my ($scfg, $volname) = @_;
6213 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6220 sub qemu_drive_mirror
{
6221 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6223 $jobs = {} if !$jobs;
6227 $jobs->{"drive-$drive"} = {};
6229 if ($dst_volid =~ /^nbd:/) {
6230 $qemu_target = $dst_volid;
6233 my $storecfg = PVE
::Storage
::config
();
6234 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6236 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6238 $format = qemu_img_format
($dst_scfg, $dst_volname);
6240 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6242 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6245 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6246 $opts->{format
} = $format if $format;
6248 print "drive mirror is starting for drive-$drive\n";
6250 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6253 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6254 die "mirroring error: $err";
6257 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6260 sub qemu_drive_mirror_monitor
{
6261 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6264 my $err_complete = 0;
6267 die "storage migration timed out\n" if $err_complete > 300;
6269 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6271 my $running_mirror_jobs = {};
6272 foreach my $stat (@$stats) {
6273 next if $stat->{type
} ne 'mirror';
6274 $running_mirror_jobs->{$stat->{device
}} = $stat;
6277 my $readycounter = 0;
6279 foreach my $job (keys %$jobs) {
6281 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6282 print "$job : finished\n";
6283 delete $jobs->{$job};
6287 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6289 my $busy = $running_mirror_jobs->{$job}->{busy
};
6290 my $ready = $running_mirror_jobs->{$job}->{ready
};
6291 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6292 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6293 my $remaining = $total - $transferred;
6294 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6296 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6299 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6302 last if scalar(keys %$jobs) == 0;
6304 if ($readycounter == scalar(keys %$jobs)) {
6305 print "all mirroring jobs are ready \n";
6306 last if $skipcomplete; #do the complete later
6308 if ($vmiddst && $vmiddst != $vmid) {
6309 my $agent_running = $qga && qga_check_running
($vmid);
6310 if ($agent_running) {
6311 print "freeze filesystem\n";
6312 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6314 print "suspend vm\n";
6315 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6318 # if we clone a disk for a new target vm, we don't switch the disk
6319 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6321 if ($agent_running) {
6322 print "unfreeze filesystem\n";
6323 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6325 print "resume vm\n";
6326 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6332 foreach my $job (keys %$jobs) {
6333 # try to switch the disk if source and destination are on the same guest
6334 print "$job: Completing block job...\n";
6336 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6337 if ($@ =~ m/cannot be completed/) {
6338 print "$job: Block job cannot be completed, try again.\n";
6341 print "$job: Completed successfully.\n";
6342 $jobs->{$job}->{complete
} = 1;
6353 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6354 die "mirroring error: $err";
6359 sub qemu_blockjobs_cancel
{
6360 my ($vmid, $jobs) = @_;
6362 foreach my $job (keys %$jobs) {
6363 print "$job: Cancelling block job\n";
6364 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6365 $jobs->{$job}->{cancel
} = 1;
6369 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6371 my $running_jobs = {};
6372 foreach my $stat (@$stats) {
6373 $running_jobs->{$stat->{device
}} = $stat;
6376 foreach my $job (keys %$jobs) {
6378 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6379 print "$job: Done.\n";
6380 delete $jobs->{$job};
6384 last if scalar(keys %$jobs) == 0;
6391 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6392 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6397 print "create linked clone of drive $drivename ($drive->{file})\n";
6398 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6399 push @$newvollist, $newvolid;
6402 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6403 $storeid = $storage if $storage;
6405 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6406 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6408 print "create full clone of drive $drivename ($drive->{file})\n";
6410 if (drive_is_cloudinit
($drive)) {
6411 $name = "vm-$newvmid-cloudinit";
6412 # cloudinit only supports raw and qcow2 atm:
6413 if ($dst_format eq 'qcow2') {
6415 } elsif ($dst_format ne 'raw') {
6416 die "clone: unhandled format for cloudinit image\n";
6419 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6420 push @$newvollist, $newvolid;
6422 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6424 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6425 if (!$running || $snapname) {
6426 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6429 my $kvmver = get_running_qemu_version
($vmid);
6430 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6431 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6432 if $drive->{iothread
};
6435 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6439 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6442 $disk->{format
} = undef;
6443 $disk->{file
} = $newvolid;
6444 $disk->{size
} = $size;
6449 # this only works if VM is running
6450 sub get_current_qemu_machine
{
6453 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6454 my $res = vm_qmp_command
($vmid, $cmd);
6456 my ($current, $default);
6457 foreach my $e (@$res) {
6458 $default = $e->{name
} if $e->{'is-default'};
6459 $current = $e->{name
} if $e->{'is-current'};
6462 # fallback to the default machine if current is not supported by qemu
6463 return $current || $default || 'pc';
6466 sub get_running_qemu_version
{
6468 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6469 my $res = vm_qmp_command
($vmid, $cmd);
6470 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6473 sub qemu_machine_feature_enabled
{
6474 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6479 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6481 $current_major = $3;
6482 $current_minor = $4;
6484 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6486 $current_major = $1;
6487 $current_minor = $2;
6490 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6495 sub qemu_machine_pxe
{
6496 my ($vmid, $conf, $machine) = @_;
6498 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6500 foreach my $opt (keys %$conf) {
6501 next if $opt !~ m/^net(\d+)$/;
6502 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6504 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6505 return $machine.".pxe" if $romfile =~ m/pxe/;
6512 sub qemu_use_old_bios_files
{
6513 my ($machine_type) = @_;
6515 return if !$machine_type;
6517 my $use_old_bios_files = undef;
6519 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6521 $use_old_bios_files = 1;
6523 my $kvmver = kvm_user_version
();
6524 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6525 # load new efi bios files on migration. So this hack is required to allow
6526 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6527 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6528 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6531 return ($use_old_bios_files, $machine_type);
6534 sub create_efidisk
{
6535 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6537 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6539 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6540 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6541 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6543 my $path = PVE
::Storage
::path
($storecfg, $volid);
6545 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6547 die "Copying EFI vars image failed: $@" if $@;
6549 return ($volid, $vars_size);
6556 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6557 my (undef, $id, $function) = @_;
6558 my $res = { id
=> $id, function
=> $function};
6559 push @{$devices->{$id}}, $res;
6562 # Entries should be sorted by functions.
6563 foreach my $id (keys %$devices) {
6564 my $dev = $devices->{$id};
6565 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6571 sub vm_iothreads_list
{
6574 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6577 foreach my $iothread (@$res) {
6578 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6585 my ($conf, $drive) = @_;
6589 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6591 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6597 my $controller = int($drive->{index} / $maxdev);
6598 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6600 return ($maxdev, $controller, $controller_prefix);
6603 sub add_hyperv_enlightenments
{
6604 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6606 return if $winversion < 6;
6607 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6609 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6611 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6612 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6613 push @$cpuFlags , 'hv_vapic';
6614 push @$cpuFlags , 'hv_time';
6616 push @$cpuFlags , 'hv_spinlocks=0xffff';
6619 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6620 push @$cpuFlags , 'hv_reset';
6621 push @$cpuFlags , 'hv_vpindex';
6622 push @$cpuFlags , 'hv_runtime';
6625 if ($winversion >= 7) {
6626 push @$cpuFlags , 'hv_relaxed';
6630 sub windows_version
{
6633 return 0 if !$ostype;
6637 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6639 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6641 } elsif ($ostype =~ m/^win(\d+)$/) {
6648 sub resolve_dst_disk_format
{
6649 my ($storecfg, $storeid, $src_volname, $format) = @_;
6650 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6653 # if no target format is specified, use the source disk format as hint
6655 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6656 $format = qemu_img_format
($scfg, $src_volname);
6662 # test if requested format is supported - else use default
6663 my $supported = grep { $_ eq $format } @$validFormats;
6664 $format = $defFormat if !$supported;
6668 sub resolve_first_disk
{
6670 my @disks = PVE
::QemuServer
::valid_drive_names
();
6672 foreach my $ds (reverse @disks) {
6673 next if !$conf->{$ds};
6674 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6675 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6681 sub generate_smbios1_uuid
{
6682 my ($uuid, $uuid_str);
6683 UUID
::generate
($uuid);
6684 UUID
::unparse
($uuid, $uuid_str);
6685 return "uuid=$uuid_str";
6688 # bash completion helper
6690 sub complete_backup_archives
{
6691 my ($cmdname, $pname, $cvalue) = @_;
6693 my $cfg = PVE
::Storage
::config
();
6697 if ($cvalue =~ m/^([^:]+):/) {
6701 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6704 foreach my $id (keys %$data) {
6705 foreach my $item (@{$data->{$id}}) {
6706 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6707 push @$res, $item->{volid
} if defined($item->{volid
});
6714 my $complete_vmid_full = sub {
6717 my $idlist = vmstatus
();
6721 foreach my $id (keys %$idlist) {
6722 my $d = $idlist->{$id};
6723 if (defined($running)) {
6724 next if $d->{template
};
6725 next if $running && $d->{status
} ne 'running';
6726 next if !$running && $d->{status
} eq 'running';
6735 return &$complete_vmid_full();
6738 sub complete_vmid_stopped
{
6739 return &$complete_vmid_full(0);
6742 sub complete_vmid_running
{
6743 return &$complete_vmid_full(1);
6746 sub complete_storage
{
6748 my $cfg = PVE
::Storage
::config
();
6749 my $ids = $cfg->{ids
};
6752 foreach my $sid (keys %$ids) {
6753 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6754 next if !$ids->{$sid}->{content
}->{images
};